// // CheckboxGroup.swift // VDS // // Created by Matt Bruce on 8/23/22. // import Foundation import UIKit import VDSCoreTokens /// When the choice has multiple options, use a checkbox group. For example, use a checkbox group when /// asking a customer which attributes they would like to filter their search by. This uses ``CheckboxItem`` /// to allow user selection. @objc(VDSCheckboxGroup) open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSelect { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- required public init() { super.init(frame: .zero) } public override init(frame: CGRect) { super.init(frame: .zero) } public required init?(coder: NSCoder) { super.init(coder: coder) } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- public var inputId: String? public var value: [SelectorItemType]? { selectedItems } /// Array of ``CheckboxItemModel`` that will be used to build the selectorViews of type ``CheckboxItem``. open var selectorModels: [CheckboxItemModel]? { didSet { if let selectorModels { items = selectorModels.enumerated().map { index, model in return CheckboxItem().with { $0.isEnabled = model.enabled $0.surface = model.surface $0.inputId = model.inputId $0.hiddenValue = model.value $0.labelText = model.labelText $0.labelTextAttributes = model.labelTextAttributes $0.childText = model.childText $0.childTextAttributes = model.childTextAttributes $0.isSelected = model.selected $0.errorText = model.errorText $0.showError = model.showError $0.selectorView.bridge_accessibilityValueBlock = { "item \(index+1) of \(selectorModels.count)" } } } } setNeedsUpdate() } } private var _showError: Bool = false /// Whether not to show the error. open var showError: Bool { get { _showError } set { var newShowError = newValue if hasSelectedItem && newShowError { newShowError = false } items.forEach { $0.showError = newShowError } _showError = newShowError } } //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. open override func setup() { super.setup() mainStackView.spacing = VDSLayout.space6X } open override func setDefaults() { super.setDefaults() showError = false inputId = nil } open override func didSelect(_ selectedControl: CheckboxItem) { selectedControl.toggle() if selectedControl.isSelected, showError{ showError.toggle() } valueChanged() } open override func reset() { super.reset() showError = false } } extension CheckboxGroup { public struct CheckboxItemModel : Surfaceable, Initable, Errorable, Equatable { /// Whether this object is enabled or not public var enabled: Bool /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public var inputId: String? public var value: AnyHashable? public var accessibileText: String? public var labelText: String? /// Array of LabelAttributeModel objects used in rendering the labeText. public var labelTextAttributes: [any LabelAttributeModel]? public var childText: String? /// Array of LabelAttributeModel objects used in rendering the childText. public var childTextAttributes: [any LabelAttributeModel]? public var selected: Bool /// Whether not to show the error. public var showError: Bool public var errorText: String? public init(enabled: Bool, surface: Surface = .light, inputId: String? = nil, value: AnyHashable? = nil, accessibileText: String? = nil, labelText: String? = nil, labelTextAttributes: [any LabelAttributeModel]? = nil, childText: String? = nil, childTextAttributes: [any LabelAttributeModel]? = nil, selected: Bool = false, showError: Bool = false, errorText: String? = nil) { self.enabled = enabled self.surface = surface self.inputId = inputId self.value = value self.accessibileText = accessibileText self.labelText = labelText self.labelTextAttributes = labelTextAttributes self.childText = childText self.childTextAttributes = childTextAttributes self.selected = selected self.showError = showError self.errorText = errorText } public init() { self.init(enabled: true) } public static func == (lhs: CheckboxGroup.CheckboxItemModel, rhs: CheckboxGroup.CheckboxItemModel) -> Bool { lhs.enabled == rhs.enabled && lhs.surface == rhs.surface && lhs.inputId == rhs.inputId && lhs.value == rhs.value && lhs.accessibileText == rhs.accessibileText && lhs.labelText == rhs.labelText && lhs.labelTextAttributes == rhs.labelTextAttributes && lhs.childText == rhs.childText && lhs.childTextAttributes == rhs.childTextAttributes && lhs.selected == rhs.selected && lhs.showError == rhs.showError && lhs.errorText == rhs.errorText } } }