mirror of
https://github.com/bitwarden/ios.git
synced 2025-12-11 04:34:55 -06:00
[PM-26064] Consolidate form fields (#2032)
This commit is contained in:
parent
07176cd3c0
commit
af42bd42c7
@ -1,125 +0,0 @@
|
||||
import BitwardenKit
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - FormMenuField
|
||||
|
||||
/// The data necessary for displaying a `FormMenuFieldView`.
|
||||
///
|
||||
struct FormMenuField<State, T: Menuable>: Equatable, Identifiable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The accessibility identifier to apply to the field.
|
||||
let accessibilityIdentifier: String?
|
||||
|
||||
/// The footer text displayed below the menu field.
|
||||
let footer: String?
|
||||
|
||||
/// A key path for updating the backing value for the menu field.
|
||||
let keyPath: WritableKeyPath<State, T>
|
||||
|
||||
/// The options displayed in the menu.
|
||||
let options: [T]
|
||||
|
||||
/// The current selection.
|
||||
let selection: T
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
"FormMenuField-\(title)"
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
/// Initialize a `FormMenuField`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - accessibilityIdentifier: The accessibility identifier given to the menu field.
|
||||
/// - footer: The footer text displayed below the menu field.
|
||||
/// - keyPath: A key path for updating the backing value for the menu field.
|
||||
/// - options: The options displayed in the menu.
|
||||
/// - selection: The current selection.
|
||||
/// - title: The title of the field.
|
||||
init(
|
||||
accessibilityIdentifier: String?,
|
||||
footer: String? = nil,
|
||||
keyPath: WritableKeyPath<State, T>,
|
||||
options: [T],
|
||||
selection: T,
|
||||
title: String,
|
||||
) {
|
||||
self.accessibilityIdentifier = accessibilityIdentifier
|
||||
self.footer = footer
|
||||
self.keyPath = keyPath
|
||||
self.options = options
|
||||
self.selection = selection
|
||||
self.title = title
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - FormMenuFieldView
|
||||
|
||||
/// A view that displays a menu field for display in a form.
|
||||
///
|
||||
struct FormMenuFieldView<State, T: Menuable, TrailingContent: View>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// A closure containing the action to take when the menu selection is changed.
|
||||
let action: (T) -> Void
|
||||
|
||||
/// The data for displaying the field.
|
||||
let field: FormMenuField<State, T>
|
||||
|
||||
/// Optional content view that is displayed to the right of the menu value.
|
||||
let trailingContent: TrailingContent
|
||||
|
||||
// MARK: View
|
||||
|
||||
var body: some View {
|
||||
BitwardenMenuField(
|
||||
title: field.title,
|
||||
footer: field.footer,
|
||||
accessibilityIdentifier: field.accessibilityIdentifier,
|
||||
options: field.options,
|
||||
selection: Binding(get: { field.selection }, set: action),
|
||||
trailingContent: { trailingContent },
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
/// Initialize a `FormMenuFieldView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - field: The data for displaying the field.
|
||||
/// - action: A closure containing the action to take when the menu selection is changed.
|
||||
///
|
||||
init(
|
||||
field: FormMenuField<State, T>,
|
||||
action: @escaping (T) -> Void,
|
||||
) where TrailingContent == EmptyView {
|
||||
self.action = action
|
||||
self.field = field
|
||||
trailingContent = EmptyView()
|
||||
}
|
||||
|
||||
/// Initialize a `FormMenuFieldView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - field: The data for displaying the field.
|
||||
/// - action: A closure containing the action to take when the menu selection is changed.
|
||||
/// - trailingContent: Optional content view that is displayed to the right of the menu value.
|
||||
///
|
||||
init(
|
||||
field: FormMenuField<State, T>,
|
||||
action: @escaping (T) -> Void,
|
||||
trailingContent: @escaping () -> TrailingContent,
|
||||
) {
|
||||
self.action = action
|
||||
self.field = field
|
||||
self.trailingContent = trailingContent()
|
||||
}
|
||||
}
|
||||
@ -1,108 +0,0 @@
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - SliderField
|
||||
|
||||
/// The data necessary for displaying a `SliderFieldView`.
|
||||
///
|
||||
struct SliderField<State>: Equatable, Identifiable {
|
||||
// MARK: Properties
|
||||
|
||||
/// A key path for updating the backing value for the slider field.
|
||||
let keyPath: WritableKeyPath<State, Double>
|
||||
|
||||
/// The range of allowable values for the slider.
|
||||
let range: ClosedRange<Double>
|
||||
|
||||
/// The accessibility id for the slider. The `title` will be used as the accessibility id
|
||||
/// if this is `nil`.
|
||||
let sliderAccessibilityId: String?
|
||||
|
||||
/// The accessibility id for the slider value. The `id` will be used as the accessibility id
|
||||
/// if this is `nil`.
|
||||
let sliderValueAccessibilityId: String?
|
||||
|
||||
/// The distance between each valid value.
|
||||
let step: Double
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
|
||||
/// The current slider value.
|
||||
let value: Double
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
"SliderField-\(title)"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SliderFieldView
|
||||
|
||||
/// A view that displays a slider for display in a form.
|
||||
///
|
||||
struct SliderFieldView<State>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// The data for displaying the field.
|
||||
let field: SliderField<State>
|
||||
|
||||
/// A closure containing the action to take when the slider begins or ends editing.
|
||||
let onEditingChanged: (Bool) -> Void
|
||||
|
||||
/// A closure containing the action to take when a new value is selected.
|
||||
let onValueChanged: (Double) -> Void
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 8) {
|
||||
HStack {
|
||||
Text(field.title)
|
||||
.styleGuide(.body)
|
||||
.foregroundColor(Asset.Colors.textPrimary.swiftUIColor)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(String(Int(field.value)))
|
||||
.styleGuide(.body, monoSpacedDigit: true)
|
||||
.foregroundColor(Asset.Colors.textSecondary.swiftUIColor)
|
||||
.accessibilityIdentifier(field.sliderValueAccessibilityId ?? field.id)
|
||||
}
|
||||
.accessibilityHidden(true)
|
||||
|
||||
Divider()
|
||||
|
||||
Slider(
|
||||
value: Binding(get: { field.value }, set: onValueChanged),
|
||||
in: field.range,
|
||||
step: field.step,
|
||||
onEditingChanged: onEditingChanged,
|
||||
)
|
||||
.tint(Asset.Colors.primaryBitwarden.swiftUIColor)
|
||||
.accessibilityLabel(field.title)
|
||||
.accessibilityIdentifier(field.sliderAccessibilityId ?? field.title)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 8)
|
||||
.background(Asset.Colors.backgroundPrimary.swiftUIColor)
|
||||
.cornerRadius(10)
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
/// Initialize a `SliderFieldView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - field: The data for displaying the field.
|
||||
/// - onEditingChanged: A closure containing the action to take when the slider begins or ends editing.
|
||||
/// - onValueChanged: A closure containing the action to take when a new value is selected.
|
||||
///
|
||||
init(
|
||||
field: SliderField<State>,
|
||||
onEditingChanged: @escaping (Bool) -> Void = { _ in },
|
||||
onValueChanged: @escaping (Double) -> Void,
|
||||
) {
|
||||
self.field = field
|
||||
self.onEditingChanged = onEditingChanged
|
||||
self.onValueChanged = onValueChanged
|
||||
}
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - StepperField
|
||||
|
||||
/// The data necessary for displaying a `StepperFieldView`.
|
||||
///
|
||||
struct StepperField<State>: Equatable, Identifiable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The accessibility id for the stepper. The `id` will be used as the accessibility id
|
||||
/// if this is `nil`.
|
||||
let accessibilityId: String?
|
||||
|
||||
/// A key path for updating the backing value for the stepper field.
|
||||
let keyPath: WritableKeyPath<State, Int>
|
||||
|
||||
/// The range of allowable values for the stepper.
|
||||
let range: ClosedRange<Int>
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
|
||||
/// The current stepper value.
|
||||
let value: Int
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
"StepperField-\(title)"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - StepperFieldView
|
||||
|
||||
/// A view that displays a stepper for display in a form.
|
||||
///
|
||||
struct StepperFieldView<State>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// A closure containing the action to take when a new value is selected.
|
||||
let action: (Int) -> Void
|
||||
|
||||
/// The data for displaying the field.
|
||||
let field: StepperField<State>
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 16) {
|
||||
Stepper(
|
||||
value: Binding(get: { field.value }, set: action),
|
||||
in: field.range,
|
||||
) {
|
||||
HStack {
|
||||
Text(field.title)
|
||||
.styleGuide(.body)
|
||||
.foregroundColor(Asset.Colors.textPrimary.swiftUIColor)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(String(field.value))
|
||||
.styleGuide(.body, monoSpacedDigit: true)
|
||||
.foregroundColor(Asset.Colors.textSecondary.swiftUIColor)
|
||||
}
|
||||
.padding(.trailing, 4)
|
||||
}
|
||||
.padding(.top, 4)
|
||||
.accessibilityIdentifier(field.accessibilityId ?? field.id)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
/// Initialize a `StepperFieldView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - field: The data for displaying the field.
|
||||
/// - action: A closure containing the action to take when a new value is selected.
|
||||
///
|
||||
init(field: StepperField<State>, action: @escaping (Int) -> Void) {
|
||||
self.action = action
|
||||
self.field = field
|
||||
}
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - ToggleField
|
||||
|
||||
/// The data necessary for displaying a `ToggleFieldView`.
|
||||
///
|
||||
struct ToggleField<State>: Equatable, Identifiable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The accessibility id for the toggle. The `id` will be used as the accessibility id
|
||||
/// if this is `nil`.
|
||||
let accessibilityId: String?
|
||||
|
||||
/// The accessibility label for the toggle. The title will be used as the accessibility label
|
||||
/// if this is `nil`.
|
||||
let accessibilityLabel: String?
|
||||
|
||||
/// Whether the toggle is disabled.
|
||||
let isDisabled: Bool
|
||||
|
||||
/// The current toggle value.
|
||||
let isOn: Bool
|
||||
|
||||
/// A key path for updating the backing value for the toggle field.
|
||||
let keyPath: WritableKeyPath<State, Bool>
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
"ToggleField-\(title)"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ToggleFieldView
|
||||
|
||||
/// A view that displays a toggle for display in a form.
|
||||
///
|
||||
struct ToggleFieldView<State>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// A closure containing the action to take when the toggle is toggled.
|
||||
let action: (Bool) -> Void
|
||||
|
||||
/// The data for displaying the field.
|
||||
let field: ToggleField<State>
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Toggle(
|
||||
field.title,
|
||||
isOn: Binding(get: { field.isOn }, set: action),
|
||||
)
|
||||
.accessibilityIdentifier(field.accessibilityId ?? field.id)
|
||||
.accessibilityLabel(field.accessibilityLabel ?? field.title)
|
||||
.disabled(field.isDisabled)
|
||||
.toggleStyle(.bitwarden)
|
||||
.padding(.bottom, 16)
|
||||
.padding(.top, 4)
|
||||
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
/// Initialize a `ToggleFieldView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - field: The data for displaying the field.
|
||||
/// - action: A closure containing the action to take when the toggle is toggled.
|
||||
///
|
||||
init(field: ToggleField<State>, action: @escaping (Bool) -> Void) {
|
||||
self.action = action
|
||||
self.field = field
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@ import Foundation
|
||||
|
||||
// MARK: - Int
|
||||
|
||||
extension Int {
|
||||
public extension Int {
|
||||
// MARK: Properties
|
||||
|
||||
/// Returns the number of digits within the value.
|
||||
@ -1,8 +1,7 @@
|
||||
import BitwardenKit
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import BitwardenShared
|
||||
|
||||
class IntTests: BitwardenTestCase {
|
||||
// MARK: Tests
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
// swiftlint:disable:this file_name
|
||||
import BitwardenKit
|
||||
import SnapshotTesting
|
||||
import XCTest
|
||||
|
||||
@testable import BitwardenShared
|
||||
|
||||
// MARK: - BitwardenSliderTests
|
||||
|
||||
class BitwardenSliderTests: BitwardenTestCase {
|
||||
@ -3,7 +3,7 @@ import SwiftUI
|
||||
|
||||
/// A custom slider view that allows for custom styling and accessibility.
|
||||
///
|
||||
struct BitwardenSlider: View {
|
||||
public struct BitwardenSlider: View {
|
||||
// MARK: Private Properties
|
||||
|
||||
/// The size of the thumb view.
|
||||
@ -31,7 +31,7 @@ struct BitwardenSlider: View {
|
||||
/// The color of the filled portion of the slider track.
|
||||
var filledTrackColor: Color = SharedAsset.Colors.sliderFilled.swiftUIColor
|
||||
|
||||
var body: some View {
|
||||
public var body: some View {
|
||||
GeometryReader { geometry in
|
||||
let thumbPosition = thumbPosition(in: geometry.size)
|
||||
ZStack {
|
||||
@ -103,7 +103,7 @@ struct BitwardenSlider: View {
|
||||
/// - trackColor: The color of the slider track.
|
||||
/// - filledTrackColor: The color of the filled portion of the slider track.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
value: Binding<Double>,
|
||||
in range: ClosedRange<Double>,
|
||||
step: Double,
|
||||
@ -1,4 +1,3 @@
|
||||
import BitwardenKit
|
||||
import BitwardenResources
|
||||
import SwiftUI
|
||||
|
||||
@ -6,7 +5,7 @@ import SwiftUI
|
||||
|
||||
/// A custom stepper component which performs increment and decrement actions.
|
||||
///
|
||||
struct BitwardenStepper<Label: View, Footer: View>: View {
|
||||
public struct BitwardenStepper<Label: View, Footer: View>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// Whether a text field can be used to type in the value as an alternative to using the
|
||||
@ -66,7 +65,7 @@ struct BitwardenStepper<Label: View, Footer: View>: View {
|
||||
|
||||
// MARK: View
|
||||
|
||||
var body: some View {
|
||||
public var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
contentView()
|
||||
|
||||
@ -87,7 +86,7 @@ struct BitwardenStepper<Label: View, Footer: View>: View {
|
||||
/// - label: The label to display for the stepper.
|
||||
/// - footer: A footer to display below the stepper.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
value: Binding<Int>,
|
||||
in range: ClosedRange<Int>,
|
||||
allowTextFieldInput: Bool = false,
|
||||
@ -113,7 +112,7 @@ struct BitwardenStepper<Label: View, Footer: View>: View {
|
||||
/// - textFieldAccessibilityIdentifier: An accessibility identifier for the text field.
|
||||
/// - label: The label to display for the stepper.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
value: Binding<Int>,
|
||||
in range: ClosedRange<Int>,
|
||||
allowTextFieldInput: Bool = false,
|
||||
@ -1,34 +1,33 @@
|
||||
import BitwardenKit
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - FormMenuField
|
||||
|
||||
/// The data necessary for displaying a `FormMenuFieldView`.
|
||||
///
|
||||
struct FormMenuField<State, T: Menuable>: Equatable, Identifiable {
|
||||
public struct FormMenuField<State, T: Menuable>: Equatable, Identifiable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The accessibility identifier to apply to the field.
|
||||
let accessibilityIdentifier: String?
|
||||
|
||||
/// The footer text displayed below the menu field.
|
||||
let footer: String?
|
||||
public let footer: String?
|
||||
|
||||
/// A key path for updating the backing value for the menu field.
|
||||
let keyPath: WritableKeyPath<State, T>
|
||||
|
||||
/// The options displayed in the menu.
|
||||
let options: [T]
|
||||
public let options: [T]
|
||||
|
||||
/// The current selection.
|
||||
let selection: T
|
||||
public let selection: T
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
public let title: String
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
public var id: String {
|
||||
"FormMenuField-\(title)"
|
||||
}
|
||||
|
||||
@ -43,7 +42,7 @@ struct FormMenuField<State, T: Menuable>: Equatable, Identifiable {
|
||||
/// - options: The options displayed in the menu.
|
||||
/// - selection: The current selection.
|
||||
/// - title: The title of the field.
|
||||
init(
|
||||
public init(
|
||||
accessibilityIdentifier: String?,
|
||||
footer: String? = nil,
|
||||
keyPath: WritableKeyPath<State, T>,
|
||||
@ -64,7 +63,7 @@ struct FormMenuField<State, T: Menuable>: Equatable, Identifiable {
|
||||
|
||||
/// A view that displays a menu field for display in a form.
|
||||
///
|
||||
struct FormMenuFieldView<State, T: Menuable, TitleAccessory: View, TrailingContent: View>: View {
|
||||
public struct FormMenuFieldView<State, T: Menuable, TitleAccessory: View, TrailingContent: View>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// A closure containing the action to take when the menu selection is changed.
|
||||
@ -81,7 +80,7 @@ struct FormMenuFieldView<State, T: Menuable, TitleAccessory: View, TrailingConte
|
||||
|
||||
// MARK: View
|
||||
|
||||
var body: some View {
|
||||
public var body: some View {
|
||||
if let trailingContent, let titleAccessoryContent {
|
||||
BitwardenMenuField(
|
||||
title: field.title,
|
||||
@ -129,7 +128,7 @@ struct FormMenuFieldView<State, T: Menuable, TitleAccessory: View, TrailingConte
|
||||
/// - field: The data for displaying the field.
|
||||
/// - action: A closure containing the action to take when the menu selection is changed.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
field: FormMenuField<State, T>,
|
||||
action: @escaping (T) -> Void,
|
||||
) where TrailingContent == EmptyView, TitleAccessory == EmptyView {
|
||||
@ -146,7 +145,7 @@ struct FormMenuFieldView<State, T: Menuable, TitleAccessory: View, TrailingConte
|
||||
/// - action: A closure containing the action to take when the menu selection is changed.
|
||||
/// - trailingContent: Optional content view that is displayed to the right of the menu value.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
field: FormMenuField<State, T>,
|
||||
action: @escaping (T) -> Void,
|
||||
trailingContent: @escaping () -> TrailingContent,
|
||||
@ -164,7 +163,7 @@ struct FormMenuFieldView<State, T: Menuable, TitleAccessory: View, TrailingConte
|
||||
/// - action: A closure containing the action to take when the menu selection is changed.
|
||||
/// - titleAccessoryContent: Optional title accessory view that is displayed to the right of the title.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
field: FormMenuField<State, T>,
|
||||
action: @escaping (T) -> Void,
|
||||
titleAccessoryContent: @escaping () -> TitleAccessory,
|
||||
@ -183,7 +182,7 @@ struct FormMenuFieldView<State, T: Menuable, TitleAccessory: View, TrailingConte
|
||||
/// - titleAccessoryContent: Optional title accessory view that is displayed to the right of the title.
|
||||
/// - trailingContent: Optional content view that is displayed to the right of the menu value.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
field: FormMenuField<State, T>,
|
||||
action: @escaping (T) -> Void,
|
||||
titleAccessoryContent: () -> TitleAccessory,
|
||||
@ -1,16 +1,15 @@
|
||||
import BitwardenKit
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - FormTextField
|
||||
|
||||
/// The data necessary for displaying a `FormTextFieldView`.
|
||||
///
|
||||
struct FormTextField<State>: Equatable, Identifiable {
|
||||
public struct FormTextField<State>: Equatable, Identifiable {
|
||||
// MARK: Types
|
||||
|
||||
/// An enum describing the behavior for when the input should be automatically capitalized.
|
||||
///
|
||||
enum Autocapitalization {
|
||||
public enum Autocapitalization {
|
||||
/// Input is never capitalized.
|
||||
case never
|
||||
|
||||
@ -49,13 +48,13 @@ struct FormTextField<State>: Equatable, Identifiable {
|
||||
let isPasswordVisible: Bool?
|
||||
|
||||
/// A key path for updating whether a password displayed in the text field is visible.
|
||||
let isPasswordVisibleKeyPath: WritableKeyPath<State, Bool>?
|
||||
public let isPasswordVisibleKeyPath: WritableKeyPath<State, Bool>?
|
||||
|
||||
/// The type of keyboard to display.
|
||||
let keyboardType: UIKeyboardType
|
||||
|
||||
/// A key path for updating the backing value for the text field.
|
||||
let keyPath: WritableKeyPath<State, String>
|
||||
public let keyPath: WritableKeyPath<State, String>
|
||||
|
||||
/// The accessibility id for the button to toggle password visibility.
|
||||
let passwordVisibilityAccessibilityId: String?
|
||||
@ -64,14 +63,14 @@ struct FormTextField<State>: Equatable, Identifiable {
|
||||
let textContentType: UITextContentType?
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
public let title: String
|
||||
|
||||
/// The current text value.
|
||||
let value: String
|
||||
public let value: String
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
public var id: String {
|
||||
"FormTextField-\(title)"
|
||||
}
|
||||
|
||||
@ -94,7 +93,7 @@ struct FormTextField<State>: Equatable, Identifiable {
|
||||
/// - textContentType: The expected type of content input in the text field. Defaults to `nil`.
|
||||
/// - title: The title of the field.
|
||||
/// - value: The current text value.
|
||||
init(
|
||||
public init(
|
||||
accessibilityId: String? = nil,
|
||||
autocapitalization: Autocapitalization = .sentences,
|
||||
isAutocorrectDisabled: Bool = false,
|
||||
@ -125,7 +124,7 @@ struct FormTextField<State>: Equatable, Identifiable {
|
||||
|
||||
/// A view that displays a text field for display in a form.
|
||||
///
|
||||
struct FormTextFieldView<State>: View {
|
||||
public struct FormTextFieldView<State>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// A closure containing the action to take when the text is changed.
|
||||
@ -138,7 +137,7 @@ struct FormTextFieldView<State>: View {
|
||||
/// in the text field is changed.
|
||||
let isPasswordVisibleChangedAction: ((Bool) -> Void)?
|
||||
|
||||
var body: some View {
|
||||
public var body: some View {
|
||||
BitwardenTextField(
|
||||
title: field.title,
|
||||
text: Binding(get: { field.value }, set: action),
|
||||
@ -164,7 +163,7 @@ struct FormTextFieldView<State>: View {
|
||||
/// - isPasswordVisibleChangedAction: A closure containing the action to take when the value
|
||||
/// for whether a password is displayed in the text field is changed.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
field: FormTextField<State>,
|
||||
action: @escaping (String) -> Void,
|
||||
isPasswordVisibleChangedAction: ((Bool) -> Void)? = nil,
|
||||
@ -5,14 +5,14 @@ import SwiftUI
|
||||
|
||||
/// The data necessary for displaying a `SliderFieldView`.
|
||||
///
|
||||
struct SliderField<State>: Equatable, Identifiable {
|
||||
public struct SliderField<State>: Equatable, Identifiable {
|
||||
// MARK: Properties
|
||||
|
||||
/// A key path for updating the backing value for the slider field.
|
||||
let keyPath: WritableKeyPath<State, Double>
|
||||
public let keyPath: WritableKeyPath<State, Double>
|
||||
|
||||
/// The range of allowable values for the slider.
|
||||
let range: ClosedRange<Double>
|
||||
public let range: ClosedRange<Double>
|
||||
|
||||
/// The accessibility id for the slider. The `title` will be used as the accessibility id
|
||||
/// if this is `nil`.
|
||||
@ -23,26 +23,58 @@ struct SliderField<State>: Equatable, Identifiable {
|
||||
let sliderValueAccessibilityId: String?
|
||||
|
||||
/// The distance between each valid value.
|
||||
let step: Double
|
||||
public let step: Double
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
public let title: String
|
||||
|
||||
/// The current slider value.
|
||||
let value: Double
|
||||
public let value: Double
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
public var id: String {
|
||||
"SliderField-\(title)"
|
||||
}
|
||||
|
||||
// MARK: Initializer
|
||||
|
||||
/// Public version of synthesized initializer
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - keyPath: A key path for updating the backing value for the slider field.
|
||||
/// - range: The range of allowable values for the slider.
|
||||
/// - sliderAccessibilityId: The accessibility ID for the slider.
|
||||
/// The `title` will be used as the accessibility ID if this is `nil`.
|
||||
/// - sliderValueAccessibilityId: The accessibility ID for the slider value.
|
||||
/// The `id` will be used as the accessibility ID if this is `nil`.
|
||||
/// - step: The distance between each valid value.
|
||||
/// - title: The title of the field.
|
||||
/// - value: The current slider value.
|
||||
public init(
|
||||
keyPath: WritableKeyPath<State, Double>,
|
||||
range: ClosedRange<Double>,
|
||||
sliderAccessibilityId: String?,
|
||||
sliderValueAccessibilityId: String?,
|
||||
step: Double,
|
||||
title: String,
|
||||
value: Double,
|
||||
) {
|
||||
self.keyPath = keyPath
|
||||
self.range = range
|
||||
self.sliderAccessibilityId = sliderAccessibilityId
|
||||
self.sliderValueAccessibilityId = sliderValueAccessibilityId
|
||||
self.step = step
|
||||
self.title = title
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SliderFieldView
|
||||
|
||||
/// A view that displays a slider for display in a form.
|
||||
///
|
||||
struct SliderFieldView<State>: View {
|
||||
public struct SliderFieldView<State>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// The data for displaying the field.
|
||||
@ -57,7 +89,7 @@ struct SliderFieldView<State>: View {
|
||||
/// The width of the three digit text "000" based on the current font.
|
||||
@SwiftUI.State private var minTextWidth: CGFloat = 14
|
||||
|
||||
var body: some View {
|
||||
public var body: some View {
|
||||
HStack(alignment: .center, spacing: 16) {
|
||||
Text(field.title)
|
||||
.styleGuide(.body)
|
||||
@ -110,7 +142,7 @@ struct SliderFieldView<State>: View {
|
||||
/// - onEditingChanged: A closure containing the action to take when the slider begins or ends editing.
|
||||
/// - onValueChanged: A closure containing the action to take when a new value is selected.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
field: SliderField<State>,
|
||||
onEditingChanged: @escaping (Bool) -> Void = { _ in },
|
||||
onValueChanged: @escaping (Double) -> Void,
|
||||
@ -5,7 +5,7 @@ import SwiftUI
|
||||
|
||||
/// The data necessary for displaying a `StepperFieldView`.
|
||||
///
|
||||
struct StepperField<State>: Equatable, Identifiable {
|
||||
public struct StepperField<State>: Equatable, Identifiable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The accessibility id for the stepper. The `id` will be used as the accessibility id
|
||||
@ -13,29 +13,54 @@ struct StepperField<State>: Equatable, Identifiable {
|
||||
let accessibilityId: String?
|
||||
|
||||
/// A key path for updating the backing value for the stepper field.
|
||||
let keyPath: WritableKeyPath<State, Int>
|
||||
public let keyPath: WritableKeyPath<State, Int>
|
||||
|
||||
/// The range of allowable values for the stepper.
|
||||
let range: ClosedRange<Int>
|
||||
public let range: ClosedRange<Int>
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
public let title: String
|
||||
|
||||
/// The current stepper value.
|
||||
let value: Int
|
||||
public let value: Int
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
public var id: String {
|
||||
"StepperField-\(title)"
|
||||
}
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Public version of synthesized initializer.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - accessibilityId: The accessibility ID for the stepper.
|
||||
/// The `id` will be used as the accessibility ID if this is `nil`.
|
||||
/// - keyPath: A key path for updating the backing value for the stepper field.
|
||||
/// - range: The range of allowable values for the stepper.
|
||||
/// - title: The title of the field.
|
||||
/// - value: The current stepper value.
|
||||
public init(
|
||||
accessibilityId: String?,
|
||||
keyPath: WritableKeyPath<State, Int>,
|
||||
range: ClosedRange<Int>,
|
||||
title: String,
|
||||
value: Int,
|
||||
) {
|
||||
self.accessibilityId = accessibilityId
|
||||
self.keyPath = keyPath
|
||||
self.range = range
|
||||
self.title = title
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - StepperFieldView
|
||||
|
||||
/// A view that displays a stepper for display in a form.
|
||||
///
|
||||
struct StepperFieldView<State>: View {
|
||||
public struct StepperFieldView<State>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// A closure containing the action to take when a new value is selected.
|
||||
@ -44,7 +69,7 @@ struct StepperFieldView<State>: View {
|
||||
/// The data for displaying the field.
|
||||
let field: StepperField<State>
|
||||
|
||||
var body: some View {
|
||||
public var body: some View {
|
||||
BitwardenStepper(
|
||||
value: Binding(get: { field.value }, set: action),
|
||||
in: field.range,
|
||||
@ -64,7 +89,7 @@ struct StepperFieldView<State>: View {
|
||||
/// - field: The data for displaying the field.
|
||||
/// - action: A closure containing the action to take when a new value is selected.
|
||||
///
|
||||
init(field: StepperField<State>, action: @escaping (Int) -> Void) {
|
||||
public init(field: StepperField<State>, action: @escaping (Int) -> Void) {
|
||||
self.action = action
|
||||
self.field = field
|
||||
}
|
||||
@ -4,7 +4,7 @@ import SwiftUI
|
||||
|
||||
/// The data necessary for displaying a `ToggleFieldView`.
|
||||
///
|
||||
struct ToggleField<State>: Equatable, Identifiable {
|
||||
public struct ToggleField<State>: Equatable, Identifiable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The accessibility id for the toggle. The `id` will be used as the accessibility id
|
||||
@ -19,26 +19,55 @@ struct ToggleField<State>: Equatable, Identifiable {
|
||||
let isDisabled: Bool
|
||||
|
||||
/// The current toggle value.
|
||||
let isOn: Bool
|
||||
public let isOn: Bool
|
||||
|
||||
/// A key path for updating the backing value for the toggle field.
|
||||
let keyPath: WritableKeyPath<State, Bool>
|
||||
public let keyPath: WritableKeyPath<State, Bool>
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
public let title: String
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
public var id: String {
|
||||
"ToggleField-\(title)"
|
||||
}
|
||||
|
||||
// MARK: Initializer
|
||||
|
||||
/// Public version of synthesized initializer.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - accessibilityId: The accessibility ID for the toggle.
|
||||
/// The `id` will be used as the accessibility ID if this is `nil`.
|
||||
/// - accessibilityLabel: The accessibility label for the toggle.
|
||||
/// The title will be used as the accessibility label if this is `nil`.
|
||||
/// - isDisabled: Whether the toggle is disabled.
|
||||
/// - isOn: The current toggle value.
|
||||
/// - keyPath: A key path for updating the backing value for the toggle field.
|
||||
/// - title: The title of the field.
|
||||
public init(
|
||||
accessibilityId: String?,
|
||||
accessibilityLabel: String?,
|
||||
isDisabled: Bool,
|
||||
isOn: Bool,
|
||||
keyPath: WritableKeyPath<State, Bool>,
|
||||
title: String,
|
||||
) {
|
||||
self.accessibilityId = accessibilityId
|
||||
self.accessibilityLabel = accessibilityLabel
|
||||
self.isDisabled = isDisabled
|
||||
self.isOn = isOn
|
||||
self.keyPath = keyPath
|
||||
self.title = title
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ToggleFieldView
|
||||
|
||||
/// A view that displays a toggle for display in a form.
|
||||
///
|
||||
struct ToggleFieldView<State>: View {
|
||||
public struct ToggleFieldView<State>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// A closure containing the action to take when the toggle is toggled.
|
||||
@ -47,7 +76,7 @@ struct ToggleFieldView<State>: View {
|
||||
/// The data for displaying the field.
|
||||
let field: ToggleField<State>
|
||||
|
||||
var body: some View {
|
||||
public var body: some View {
|
||||
Toggle(
|
||||
field.title,
|
||||
isOn: Binding(get: { field.isOn }, set: action),
|
||||
@ -67,7 +96,7 @@ struct ToggleFieldView<State>: View {
|
||||
/// - field: The data for displaying the field.
|
||||
/// - action: A closure containing the action to take when the toggle is toggled.
|
||||
///
|
||||
init(field: ToggleField<State>, action: @escaping (Bool) -> Void) {
|
||||
public init(field: ToggleField<State>, action: @escaping (Bool) -> Void) {
|
||||
self.action = action
|
||||
self.field = field
|
||||
}
|
||||
@ -1,176 +0,0 @@
|
||||
import BitwardenKit
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - FormTextField
|
||||
|
||||
/// The data necessary for displaying a `FormTextFieldView`.
|
||||
///
|
||||
struct FormTextField<State>: Equatable, Identifiable {
|
||||
// MARK: Types
|
||||
|
||||
/// An enum describing the behavior for when the input should be automatically capitalized.
|
||||
///
|
||||
enum Autocapitalization {
|
||||
/// Input is never capitalized.
|
||||
case never
|
||||
|
||||
/// The first letter of a sentence should be capitalized.
|
||||
case sentences
|
||||
|
||||
/// The first letter of every word should be capitalized.
|
||||
case words
|
||||
|
||||
/// Returns the `TextInputAutocapitalization` behavior.
|
||||
var textInputAutocapitalization: TextInputAutocapitalization {
|
||||
switch self {
|
||||
case .never:
|
||||
.never
|
||||
case .sentences:
|
||||
.sentences
|
||||
case .words:
|
||||
.words
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The accessibility id for the text field. The `title` will be used as the accessibility id
|
||||
/// if this is `nil`.
|
||||
let accessibilityId: String?
|
||||
|
||||
/// The behavior for when the input should be automatically capitalized.
|
||||
let autocapitalization: Autocapitalization
|
||||
|
||||
/// Whether autocorrect is disabled in the text field.
|
||||
let isAutocorrectDisabled: Bool
|
||||
|
||||
/// Whether a password displayed in the text field is visible.
|
||||
let isPasswordVisible: Bool?
|
||||
|
||||
/// A key path for updating whether a password displayed in the text field is visible.
|
||||
let isPasswordVisibleKeyPath: WritableKeyPath<State, Bool>?
|
||||
|
||||
/// The type of keyboard to display.
|
||||
let keyboardType: UIKeyboardType
|
||||
|
||||
/// A key path for updating the backing value for the text field.
|
||||
let keyPath: WritableKeyPath<State, String>
|
||||
|
||||
/// The accessibility id for the button to toggle password visibility.
|
||||
let passwordVisibilityAccessibilityId: String?
|
||||
|
||||
/// The expected type of content input in the text field.
|
||||
let textContentType: UITextContentType?
|
||||
|
||||
/// The title of the field.
|
||||
let title: String
|
||||
|
||||
/// The current text value.
|
||||
let value: String
|
||||
|
||||
// MARK: Identifiable
|
||||
|
||||
var id: String {
|
||||
"FormTextField-\(title)"
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
/// Initialize a `FormTextField`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - accessibilityId: The accessibility id for the text field.
|
||||
/// - autocapitalization: The behavior for when the input should be automatically capitalized.
|
||||
/// Defaults to `.sentences`.
|
||||
/// - isAutocorrectDisabled: Whether autocorrect is disabled in the text field. Defaults to
|
||||
/// `false`.
|
||||
/// - isPasswordVisible: Whether a password displayed in the text field is visible
|
||||
/// - isPasswordVisibleKeyPath: A key path for updating whether a password displayed in the
|
||||
/// text field is visible.
|
||||
/// - keyboardType: The type of keyboard to display.
|
||||
/// - keyPath: A key path for updating the backing value for the text field.
|
||||
/// - passwordVisibilityAccessibilityId: The accessibility id for the password visibility button.
|
||||
/// - textContentType: The expected type of content input in the text field. Defaults to `nil`.
|
||||
/// - title: The title of the field.
|
||||
/// - value: The current text value.
|
||||
init(
|
||||
accessibilityId: String? = nil,
|
||||
autocapitalization: Autocapitalization = .sentences,
|
||||
isAutocorrectDisabled: Bool = false,
|
||||
isPasswordVisible: Bool? = nil,
|
||||
isPasswordVisibleKeyPath: WritableKeyPath<State, Bool>? = nil,
|
||||
keyboardType: UIKeyboardType = .default,
|
||||
keyPath: WritableKeyPath<State, String>,
|
||||
passwordVisibilityAccessibilityId: String? = nil,
|
||||
textContentType: UITextContentType? = nil,
|
||||
title: String,
|
||||
value: String,
|
||||
) {
|
||||
self.accessibilityId = accessibilityId
|
||||
self.autocapitalization = autocapitalization
|
||||
self.isAutocorrectDisabled = isAutocorrectDisabled
|
||||
self.isPasswordVisible = isPasswordVisible
|
||||
self.isPasswordVisibleKeyPath = isPasswordVisibleKeyPath
|
||||
self.keyboardType = keyboardType
|
||||
self.keyPath = keyPath
|
||||
self.passwordVisibilityAccessibilityId = passwordVisibilityAccessibilityId
|
||||
self.textContentType = textContentType
|
||||
self.title = title
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - FormTextFieldView
|
||||
|
||||
/// A view that displays a text field for display in a form.
|
||||
///
|
||||
struct FormTextFieldView<State>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// A closure containing the action to take when the text is changed.
|
||||
let action: (String) -> Void
|
||||
|
||||
/// The data for displaying the field.
|
||||
let field: FormTextField<State>
|
||||
|
||||
/// A closure containing the action to take when the value for whether a password is displayed
|
||||
/// in the text field is changed.
|
||||
let isPasswordVisibleChangedAction: ((Bool) -> Void)?
|
||||
|
||||
var body: some View {
|
||||
BitwardenTextField(
|
||||
title: field.title,
|
||||
text: Binding(get: { field.value }, set: action),
|
||||
accessibilityIdentifier: field.accessibilityId ?? field.title,
|
||||
passwordVisibilityAccessibilityId: field.passwordVisibilityAccessibilityId,
|
||||
isPasswordVisible: field.isPasswordVisible.map { isPasswordVisible in
|
||||
Binding(get: { isPasswordVisible }, set: isPasswordVisibleChangedAction ?? { _ in })
|
||||
},
|
||||
)
|
||||
.autocorrectionDisabled(field.isAutocorrectDisabled)
|
||||
.keyboardType(field.keyboardType)
|
||||
.textContentType(field.textContentType)
|
||||
.textInputAutocapitalization(field.autocapitalization.textInputAutocapitalization)
|
||||
}
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
/// Initialize a `FormTextFieldView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - field: The data for displaying the field.
|
||||
/// - action: A closure containing the action to take when the text is changed.
|
||||
/// - isPasswordVisibleChangedAction: A closure containing the action to take when the value
|
||||
/// for whether a password is displayed in the text field is changed.
|
||||
///
|
||||
init(
|
||||
field: FormTextField<State>,
|
||||
action: @escaping (String) -> Void,
|
||||
isPasswordVisibleChangedAction: ((Bool) -> Void)? = nil,
|
||||
) {
|
||||
self.action = action
|
||||
self.field = field
|
||||
self.isPasswordVisibleChangedAction = isPasswordVisibleChangedAction
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
import BitwardenKit
|
||||
import BitwardenResources
|
||||
import UIKit
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import BitwardenKit
|
||||
import BitwardenSdk
|
||||
import InlineSnapshotTesting
|
||||
import XCTest
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// swiftlint:disable:this file_name
|
||||
import BitwardenKit
|
||||
import BitwardenResources
|
||||
import SwiftUI
|
||||
import ViewInspector
|
||||
|
||||
@ -34,7 +34,7 @@ struct BitwardenSliderType: BaseViewType {
|
||||
static var typePrefix: String = "BitwardenSlider"
|
||||
|
||||
static var namespacedPrefixes: [String] = [
|
||||
"BitwardenShared.BitwardenSlider",
|
||||
"BitwardenKit.BitwardenSlider",
|
||||
]
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ struct BitwardenStepperType: BaseViewType {
|
||||
static var typePrefix: String = "BitwardenStepper"
|
||||
|
||||
static var namespacedPrefixes: [String] = [
|
||||
"BitwardenShared.BitwardenStepper",
|
||||
"BitwardenKit.BitwardenStepper",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user