diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 3e5d50bc..34b75bda 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -70,7 +70,6 @@ EA33617C288B19210071C351 /* VDSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33617B288B19210071C351 /* VDSTests.swift */; }; EA33617D288B19210071C351 /* VDS.h in Headers */ = {isa = PBXBuildFile; fileRef = EA33616F288B19200071C351 /* VDS.h */; settings = {ATTRIBUTES = (Public, ); }; }; EA3361A8288B23300071C351 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361A7288B23300071C351 /* UIColor.swift */; }; - EA3361AA288B25E40071C351 /* Disabling.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361A9288B25E40071C351 /* Disabling.swift */; }; EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361AE288B26310071C351 /* FormFieldable.swift */; }; EA3361B6288B2A410071C351 /* Control.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361B5288B2A410071C351 /* Control.swift */; }; EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361B7288B2AAA0071C351 /* ViewProtocol.swift */; }; @@ -102,6 +101,7 @@ EA6642952BCEBF9500D81DC4 /* TextLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6642942BCEBF9500D81DC4 /* TextLinkModel.swift */; }; EA6F330E2B911E9000BACAB9 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6F330D2B911E9000BACAB9 /* TextView.swift */; }; EA78C7962C00CAC200430AD1 /* Groupable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA78C7952C00CAC200430AD1 /* Groupable.swift */; }; + EA7AE5592C78C7D000107C74 /* ParentViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5582C78C7D000107C74 /* ParentViewProtocol.swift */; }; EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */; }; EA8141102A127066004F60D2 /* UIColor+VDSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */; }; EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; }; @@ -290,7 +290,6 @@ EA336176288B19210071C351 /* VDSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VDSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; EA33617B288B19210071C351 /* VDSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDSTests.swift; sourceTree = ""; }; EA3361A7288B23300071C351 /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - EA3361A9288B25E40071C351 /* Disabling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Disabling.swift; sourceTree = ""; }; EA3361AE288B26310071C351 /* FormFieldable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormFieldable.swift; sourceTree = ""; }; EA3361B5288B2A410071C351 /* Control.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Control.swift; sourceTree = ""; }; EA3361B7288B2AAA0071C351 /* ViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewProtocol.swift; sourceTree = ""; }; @@ -325,6 +324,7 @@ EA78C7952C00CAC200430AD1 /* Groupable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Groupable.swift; sourceTree = ""; }; EA78C7A12C0E63D200430AD1 /* vds-dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "vds-dev.xcconfig"; sourceTree = ""; }; EA78C7A22C0E63DD00430AD1 /* vds.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = vds.xcconfig; sourceTree = ""; }; + EA7AE5582C78C7D000107C74 /* ParentViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParentViewProtocol.swift; sourceTree = ""; }; EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = ""; }; EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+VDSColor.swift"; sourceTree = ""; }; EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = ""; }; @@ -771,7 +771,6 @@ EAF1FE9829D4850E00101452 /* Clickable.swift */, EAA5EEDF28F49DB3003B3210 /* Colorable.swift */, EAACB8972B92706F006A3869 /* DefaultValuing.swift */, - EA3361A9288B25E40071C351 /* Disabling.swift */, 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */, EAF978202A99035B00C2FEA9 /* Enabling.swift */, EA5E305929510F8B0082B959 /* EnumSubset.swift */, @@ -780,6 +779,7 @@ EA78C7952C00CAC200430AD1 /* Groupable.swift */, EA33624628931B050071C351 /* Initable.swift */, EA471F392A95587500CE9E58 /* LayoutConstraintable.swift */, + EA7AE5582C78C7D000107C74 /* ParentViewProtocol.swift */, EA985C7C297DAED300F2FF2E /* Primitive.swift */, EAF7F0A5289B0CE000B287F5 /* Resetable.swift */, EA3361C8289054C50071C351 /* Surfaceable.swift */, @@ -1338,6 +1338,7 @@ EAF7F0A4289B017C00B287F5 /* LabelAttributeModel.swift in Sources */, EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */, EA5F86D02A1F936100BC83E4 /* TabsContainer.swift in Sources */, + EA7AE5592C78C7D000107C74 /* ParentViewProtocol.swift in Sources */, EAF7F0B1289B177F00B287F5 /* ColorLabelAttribute.swift in Sources */, EAC9258F2911C9DE00091998 /* EntryFieldBase.swift in Sources */, 18B9763F2C11BA4A009271DF /* CarouselPaginationModel.swift in Sources */, @@ -1406,7 +1407,6 @@ EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */, EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */, 1842B1E32BECF0A20021AFCA /* CalendarFooterReusableView.swift in Sources */, - EA3361AA288B25E40071C351 /* Disabling.swift in Sources */, EA3361B6288B2A410071C351 /* Control.swift in Sources */, EAC58C122BED0DDD00BA39FA /* Text.swift in Sources */, 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */, diff --git a/VDS/BaseClasses/Selector/SelectorBase.swift b/VDS/BaseClasses/Selector/SelectorBase.swift index fe5cb8fc..9a3ee2ec 100644 --- a/VDS/BaseClasses/Selector/SelectorBase.swift +++ b/VDS/BaseClasses/Selector/SelectorBase.swift @@ -30,7 +30,8 @@ public protocol SelectorControlable: Control, Changeable { /// Base Class used to build out a Selector control. @objcMembers @objc(VDSSelectorBase) -open class SelectorBase: Control, SelectorControlable { +open class SelectorBase: Control, SelectorControlable, ParentViewProtocol { + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -49,6 +50,8 @@ open class SelectorBase: Control, SelectorControlable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [selectorView] } + open var onChangeSubscriber: AnyCancellable? open var size = CGSize(width: 20, height: 20) { didSet { setNeedsUpdate() } } diff --git a/VDS/BaseClasses/Selector/SelectorGroupBase.swift b/VDS/BaseClasses/Selector/SelectorGroupBase.swift index e04b5e5a..63556c95 100644 --- a/VDS/BaseClasses/Selector/SelectorGroupBase.swift +++ b/VDS/BaseClasses/Selector/SelectorGroupBase.swift @@ -39,7 +39,7 @@ extension SelectorGroupSingleSelect { } /// Base Class used for any Grouped Form Control of a Selector Type. -open class SelectorGroupBase: Control, SelectorGroup, Changeable { +open class SelectorGroupBase: Control, SelectorGroup, Changeable, ParentViewProtocol { //-------------------------------------------------- // MARK: - Private Properties @@ -57,6 +57,8 @@ open class SelectorGroupBase: Control, SelectorGrou //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { items } + /// Array of the HandlerType registered. /// Array of HandlerType that the user will have the ability to select from. open var items: [SelectorItemType] = [] { diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index ea037771..321df2a8 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -11,7 +11,7 @@ import Combine import VDSCoreTokens /// Base Class used to build out a SelectorControlable control. -open class SelectorItemBase: Control, Errorable, Changeable, Groupable { +open class SelectorItemBase: Control, Errorable, Changeable, Groupable, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -61,7 +61,9 @@ open class SelectorItemBase: Control, Errorable, Changea //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var onChangeSubscriber: AnyCancellable? + open var children: [any ViewProtocol] { [label, childLabel, errorLabel, selectorView] } + + open var onChangeSubscriber: AnyCancellable? /// Label used to render labelText. open var label = Label().with { diff --git a/VDS/Components/Badge/Badge.swift b/VDS/Components/Badge/Badge.swift index 1c47133f..19c40bbc 100644 --- a/VDS/Components/Badge/Badge.swift +++ b/VDS/Components/Badge/Badge.swift @@ -17,7 +17,7 @@ import Combine /// to its parent this object will stretch to the parent's width. @objcMembers @objc(VDSBadge) -open class Badge: View { +open class Badge: View, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -45,6 +45,8 @@ open class Badge: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [label] } + /// Label used to render text open var label = Label().with { $0.isAccessibilityElement = false diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index daecddf4..403c7d46 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -13,7 +13,7 @@ import Combine /// A badge indicator is a visual label used to convey status or highlight supplemental information. @objcMembers @objc(VDSBadgeIndicator) -open class BadgeIndicator: View { +open class BadgeIndicator: View, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -135,6 +135,8 @@ open class BadgeIndicator: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [label, badgeView] } + /// Label used for the numeric kind. open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index 808b5548..938a22a4 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -15,11 +15,13 @@ import Combine /// Breadcrumbs are secondary navigation that use a hierarchy of internal links to tell customers where they are in an experience. Each breadcrumb links to its respective page, except for that of current page. @objcMembers @objc(VDSBreadcrumbs) -open class Breadcrumbs: View { +open class Breadcrumbs: View, ParentViewProtocol { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { breadcrumbs } + /// Array of ``BreadcrumbItem`` views for the Breadcrumbs. open var breadcrumbs: [BreadcrumbItem] = [] { didSet { setNeedsUpdate() } } diff --git a/VDS/Components/Checkbox/CheckboxGroup.swift b/VDS/Components/Checkbox/CheckboxGroup.swift index 8268f90f..f2a62efa 100644 --- a/VDS/Components/Checkbox/CheckboxGroup.swift +++ b/VDS/Components/Checkbox/CheckboxGroup.swift @@ -44,7 +44,7 @@ open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSel if let selectorModels { items = selectorModels.enumerated().map { index, model in return CheckboxItem().with { - $0.isEnabled = !model.disabled + $0.isEnabled = model.enabled $0.surface = model.surface $0.inputId = model.inputId $0.hiddenValue = model.value @@ -110,8 +110,8 @@ open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSel extension CheckboxGroup { public struct CheckboxItemModel : Surfaceable, Initable, Errorable { - /// Whether this object is disabled or not - public var disabled: Bool + /// 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? @@ -128,8 +128,8 @@ extension CheckboxGroup { public var showError: Bool public var errorText: String? - public init(disabled: 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.disabled = disabled + 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 @@ -144,7 +144,7 @@ extension CheckboxGroup { } public init() { - self.init(disabled: false) + self.init(enabled: true) } } diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index e9137ad9..bd53a2a2 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -94,6 +94,12 @@ open class DatePicker: EntryFieldBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open override var children: [any ViewProtocol] { + var current = super.children + current.append(selectedDateLabel) + return current + } + open var calendarIcon = Icon().with { $0.name = .calendar $0.size = .medium diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 2c243a26..98a5a61f 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -31,7 +31,7 @@ open class DropdownSelect: EntryFieldBase { //-------------------------------------------------- // MARK: - Public Properties - //-------------------------------------------------- + //-------------------------------------------------- /// If true, the label will be displayed inside the dropdown containerView. Otherwise, the label will be above the dropdown containerView like a normal text input. open var showInlineLabel: Bool = false { didSet { setNeedsUpdate() }} diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index b6b51601..92be222d 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -14,7 +14,7 @@ import Combine /// It usually represents a supplementary or utilitarian action. A button icon can stand alone, but often /// exists in a group when there are several actions that can be performed. @objc(VDSButtonIcon) -open class ButtonIcon: Control, Changeable { +open class ButtonIcon: Control, Changeable, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -109,6 +109,8 @@ open class ButtonIcon: Control, Changeable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [icon] } + public var onChangeSubscriber: AnyCancellable? ///Badge Indicator object used to render for the ButtonIcon. diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 6c44b58f..1323bd25 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -70,6 +70,12 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open override var children: [any ViewProtocol] { + var current = super.children + current.append(contentsOf: [decrementButton, incrementButton, textLabel]) + return current + } + /// If there is a width that is larger than this size's minimumWidth, the input stepper will resize to this width. open var controlWidth: ControlWidth? { get { _controlWidth } diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 59d2b78f..0fb05caa 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -16,7 +16,7 @@ import Combine /// experience-wide. @objcMembers @objc(VDSNotification) -open class Notification: View { +open class Notification: View, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -101,6 +101,8 @@ open class Notification: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [typeIcon, closeButton, titleLabel, subTitleLabel, primaryButton, secondaryButton] } + /// Icon used for denoting type. open var typeIcon = Icon().with { $0.name = .infoBold diff --git a/VDS/Components/PriceLockup/PriceLockup.swift b/VDS/Components/PriceLockup/PriceLockup.swift index 990e5b76..d36fe7ee 100644 --- a/VDS/Components/PriceLockup/PriceLockup.swift +++ b/VDS/Components/PriceLockup/PriceLockup.swift @@ -11,7 +11,7 @@ import VDSCoreTokens @objcMembers @objc(VDSPriceLockup) -open class PriceLockup: View { +open class PriceLockup: View, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -90,6 +90,7 @@ open class PriceLockup: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [priceLockupLabel] } /// If true, the component will render as bold. open var bold: Bool = false { didSet { setNeedsUpdate() } } diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index 000e3433..3b17d7d8 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -49,7 +49,7 @@ open class RadioBoxGroup: SelectorGroupBase, SelectorGroupSingleSe $0.subTextAttributes = model.subTextAttributes $0.subTextRight = model.subTextRight $0.subTextRightAttributes = model.subTextRightAttributes - $0.isEnabled = !model.disabled + $0.isEnabled = model.enabled $0.inputId = model.inputId $0.hiddenValue = model.value $0.isSelected = model.selected @@ -114,8 +114,8 @@ open class RadioBoxGroup: SelectorGroupBase, SelectorGroupSingleSe extension RadioBoxGroup { public struct RadioBoxItemModel: Surfaceable, Initable, FormFieldable { - /// Whether this object is disabled or not - public var disabled: Bool + /// 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? @@ -134,12 +134,12 @@ extension RadioBoxGroup { public var strikethrough: Bool = false public var strikethroughAccessibileText: String - public init(disabled: Bool, surface: Surface = .light, inputId: String? = nil, value: String? = nil, + public init(enabled: Bool, surface: Surface = .light, inputId: String? = nil, value: String? = nil, text: String = "", textAttributes: [any LabelAttributeModel]? = nil, subText: String? = nil, subTextAttributes: [any LabelAttributeModel]? = nil, subTextRight: String? = nil, subTextRightAttributes: [any LabelAttributeModel]? = nil, selected: Bool = false, errorText: String? = nil, accessibileText: String? = nil, strikethrough: Bool = false, strikethroughAccessibileText: String = "not available") { - self.disabled = disabled + self.enabled = enabled self.surface = surface self.inputId = inputId self.value = value @@ -156,7 +156,7 @@ extension RadioBoxGroup { } public init() { - self.init(disabled: false) + self.init(enabled: true) } } } diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index a5ca1d8b..695b1261 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -14,7 +14,7 @@ import VDSCoreTokens /// that are used within a ``RadioBoxGroup``. @objcMembers @objc(VDSRadioBoxItem) -open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable { +open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -53,6 +53,8 @@ open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [textLabel, subTextLabel, subTextRightLabel, selectorView] } + open var onChangeSubscriber: AnyCancellable? /// Label used to render the text. diff --git a/VDS/Components/RadioButton/RadioButtonGroup.swift b/VDS/Components/RadioButton/RadioButtonGroup.swift index 5d323997..8bde87de 100644 --- a/VDS/Components/RadioButton/RadioButtonGroup.swift +++ b/VDS/Components/RadioButton/RadioButtonGroup.swift @@ -43,7 +43,7 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi if let selectorModels { items = selectorModels.enumerated().map { index, model in return RadioButtonItem().with { - $0.isEnabled = !model.disabled + $0.isEnabled = model.enabled $0.surface = model.surface $0.inputId = model.inputId $0.hiddenValue = model.value @@ -105,8 +105,8 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi extension RadioButtonGroup { public struct RadioButtonItemModel: Surfaceable, Initable, FormFieldable, Errorable { - /// Whether this object is disabled or not - public var disabled: Bool + /// 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? @@ -123,8 +123,8 @@ extension RadioButtonGroup { public var showError: Bool public var errorText: String? - public init(disabled: 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.disabled = disabled + 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 @@ -139,7 +139,7 @@ extension RadioButtonGroup { } public init() { - self.init(disabled: false) + self.init(enabled: true) } } } diff --git a/VDS/Components/Tabs/Tabs.swift b/VDS/Components/Tabs/Tabs.swift index ac9e7269..fe967338 100644 --- a/VDS/Components/Tabs/Tabs.swift +++ b/VDS/Components/Tabs/Tabs.swift @@ -12,7 +12,7 @@ import VDSCoreTokens /// Tabs are organizational components that group content and allow customers to navigate its display. Use them to separate content when the content is related but doesn’t need to be compared. @objcMembers @objc(VDSTabs) -open class Tabs: View { +open class Tabs: View, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -84,6 +84,8 @@ open class Tabs: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { tabViews } + /// A callback when the selectedIndex changes. Passes parameters (tabIndex). open var onTabDidSelect: ((Int) -> Void)? diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 0a815e08..8d4aeadc 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -11,7 +11,7 @@ import VDSCoreTokens import Combine /// Base Class used to build out a Input controls. -open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { +open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -155,6 +155,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalVali //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [titleLabel, helperLabel, errorLabel, statusIcon] } + /// This is the view that will be wrapped with the border for userInteraction. /// The only subview of this view is the fieldStackView open var containerView = View().with { diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index b00d0388..6c695112 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -44,7 +44,7 @@ open class TileContainer: TileContainerBase { } } -open class TileContainerBase: View where PaddingType.ValueType == CGFloat { +open class TileContainerBase: View where PaddingType.ValueType == CGFloat { //-------------------------------------------------- // MARK: - Initializers @@ -122,7 +122,7 @@ open class TileContainerBase: View where //-------------------------------------------------- // MARK: - Public Properties - //-------------------------------------------------- + //-------------------------------------------------- /// This takes an image source url and applies it as a background image. open var backgroundImage: UIImage? { didSet { setNeedsUpdate() } } @@ -340,21 +340,21 @@ open class TileContainerBase: View where open override func touchesBegan(_ touches: Set, with event: UIEvent?) { super.touchesBegan(touches, with: event) - if let onClickSubscriber { + if onClickSubscriber != nil { isHighlighted = true } } open override func touchesEnded(_ touches: Set, with event: UIEvent?) { super.touchesEnded(touches, with: event) - if let onClickSubscriber { + if onClickSubscriber != nil { isHighlighted = false } } open override func touchesCancelled(_ touches: Set, with event: UIEvent?) { super.touchesCancelled(touches, with: event) - if let onClickSubscriber { + if onClickSubscriber != nil { isHighlighted = false } } diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index cb154056..3a6e0150 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -17,7 +17,7 @@ import Combine /// function. @objcMembers @objc(VDSTilelet) -open class Tilelet: TileContainerBase { +open class Tilelet: TileContainerBase, ParentViewProtocol { /// Enum used to describe the padding choices used for this component. public enum Padding: String, DefaultValuing, Valuing, CaseIterable { @@ -110,6 +110,8 @@ open class Tilelet: TileContainerBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [badge, titleLockup, descriptiveIcon, directionalIcon] } + /// Title lockup positioned in the contentView. open var titleLockup = TitleLockup().with { $0.standardStyleConfiguration = .init(styleConfigurations: [ diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index 1711939c..ad56813b 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -14,7 +14,7 @@ import Combine /// with approved built in text size configurations. @objcMembers @objc(VDSTitleLockup) -open class TitleLockup: View { +open class TitleLockup: View, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -62,6 +62,8 @@ open class TitleLockup: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [eyebrowLabel, titleLabel, subTitleLabel] } + /// Aligns TitleLockup's subcomponent's text open var textAlignment: TextAlignment = .left { didSet { setNeedsUpdate() } } diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index 304b18ce..8c11004b 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -14,7 +14,7 @@ import Combine /// or turn off a single option, setting or function. @objcMembers @objc(VDSToggle) -open class Toggle: Control, Changeable, FormFieldable { +open class Toggle: Control, Changeable, FormFieldable, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -90,6 +90,8 @@ open class Toggle: Control, Changeable, FormFieldable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [toggleView, label] } + open var onChangeSubscriber: AnyCancellable? /// Actual toggle used in this component. diff --git a/VDS/Components/Tooltip/TooltipDialog.swift b/VDS/Components/Tooltip/TooltipDialog.swift index bb6b5653..bbccb8f5 100644 --- a/VDS/Components/Tooltip/TooltipDialog.swift +++ b/VDS/Components/Tooltip/TooltipDialog.swift @@ -11,7 +11,7 @@ import VDSCoreTokens @objcMembers @objc(VDSTooltipDialog) -open class TooltipDialog: View, UIScrollViewDelegate { +open class TooltipDialog: View, UIScrollViewDelegate, ParentViewProtocol { //-------------------------------------------------- // MARK: - Initializers @@ -55,6 +55,8 @@ open class TooltipDialog: View, UIScrollViewDelegate { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var children: [any ViewProtocol] { [titleLabel, contentLabel] } + open var tooltipModel = Tooltip.TooltipModel() { didSet { setNeedsUpdate() } } open var titleLabel = Label().with { label in diff --git a/VDS/Protocols/Disabling.swift b/VDS/Protocols/Disabling.swift deleted file mode 100644 index 12b938a7..00000000 --- a/VDS/Protocols/Disabling.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// Disabling.swift -// VDS -// -// Created by Matt Bruce on 7/22/22. -// - -import Foundation - -///// Any object that can be disabled, which may change the appearance -//public protocol Disabling { -// /// Whether this object is disabled or not -// var disabled: Bool { get set } -//} diff --git a/VDS/Protocols/ParentViewProtocol.swift b/VDS/Protocols/ParentViewProtocol.swift new file mode 100644 index 00000000..b4c07863 --- /dev/null +++ b/VDS/Protocols/ParentViewProtocol.swift @@ -0,0 +1,37 @@ +// +// ParentViewProtocol.swift +// VDS +// +// Created by Matt Bruce on 8/23/24. +// + +import Foundation + + +/// This is used in a View or Control to denote subviews of the ViewProtocol +/// type, more or less for composite views/controls. +public protocol ParentViewProtocol: ViewProtocol { + var children: [any ViewProtocol] { get } +} + +extension ParentViewProtocol { + + /// This will get all of the children for yourself as well as all + /// of the children within the full tree hierarchy. + /// - Returns: All children within the hierachy + public func getAllChildren() -> [any ViewProtocol] { + var allChildren = [any ViewProtocol]() + + func traverse(view: any ViewProtocol) { + if let parentView = view as? any ParentViewProtocol { + for child in parentView.children { + allChildren.append(child) + traverse(view: child) + } + } + } + + traverse(view: self) + return children + } +} diff --git a/VDS/Protocols/ViewProtocol.swift b/VDS/Protocols/ViewProtocol.swift index 9a509dc1..6d3dc4f3 100644 --- a/VDS/Protocols/ViewProtocol.swift +++ b/VDS/Protocols/ViewProtocol.swift @@ -38,8 +38,23 @@ extension ViewProtocol { public func setNeedsUpdate() { if shouldUpdateView { shouldUpdateView = false + + //see if this is a view that has children + let parent = self as? any ParentViewProtocol + let children = parent?.getAllChildren() + //if so turn off the shouldUpdate to keep UI + //from blocking + children?.forEach{ $0.shouldUpdateView = false } + updateView() updateAccessibility() + + //if so turn on + children?.forEach{ + $0.updateView() + $0.updateAccessibility() + $0.shouldUpdateView = true + } shouldUpdateView = true } }