diff --git a/VDSSample.xcodeproj/project.pbxproj b/VDSSample.xcodeproj/project.pbxproj index d963b41..3b70fa6 100644 --- a/VDSSample.xcodeproj/project.pbxproj +++ b/VDSSample.xcodeproj/project.pbxproj @@ -62,6 +62,7 @@ EA5E30552950EA6E0082B959 /* TitleLockupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E30542950EA6E0082B959 /* TitleLockupViewController.swift */; }; EA5E305C295111050082B959 /* TileletViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305B295111050082B959 /* TileletViewController.swift */; }; EA5F86CE2A1E863F00BC83E4 /* TabsContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5F86CD2A1E863F00BC83E4 /* TabsContainerViewController.swift */; }; + EA6642972BD1B2E700D81DC4 /* ColorPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6642962BD1B2E700D81DC4 /* ColorPickerView.swift */; }; EA81410E2A0ED8DC004F60D2 /* ButtonIconViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410D2A0ED8DC004F60D2 /* ButtonIconViewController.swift */; }; EA89201928B56DF5006B9984 /* RadioBoxGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201828B56DF5006B9984 /* RadioBoxGroupViewController.swift */; }; EA89204628B66CE2006B9984 /* ScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89203F28B66CE2006B9984 /* ScrollViewController.swift */; }; @@ -157,6 +158,7 @@ EA5E30542950EA6E0082B959 /* TitleLockupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupViewController.swift; sourceTree = ""; }; EA5E305B295111050082B959 /* TileletViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletViewController.swift; sourceTree = ""; }; EA5F86CD2A1E863F00BC83E4 /* TabsContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsContainerViewController.swift; sourceTree = ""; }; + EA6642962BD1B2E700D81DC4 /* ColorPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerView.swift; sourceTree = ""; }; EA81410D2A0ED8DC004F60D2 /* ButtonIconViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconViewController.swift; sourceTree = ""; }; EA89201828B56DF5006B9984 /* RadioBoxGroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBoxGroupViewController.swift; sourceTree = ""; }; EA89203F28B66CE2006B9984 /* ScrollViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewController.swift; sourceTree = ""; }; @@ -265,9 +267,10 @@ EA89204F28B682F4006B9984 /* Classes */ = { isa = PBXGroup; children = ( - EA89205028B68307006B9984 /* TextField.swift */, - EAD062A42A3B5CDF0015965D /* Slider.swift */, + EA6642962BD1B2E700D81DC4 /* ColorPickerView.swift */, EAB5FEF22928153D00998C17 /* Helper.swift */, + EAD062A42A3B5CDF0015965D /* Slider.swift */, + EA89205028B68307006B9984 /* TextField.swift */, ); path = Classes; sourceTree = ""; @@ -519,6 +522,7 @@ EAD062AD2A3B86950015965D /* BadgeIndicatorViewController.swift in Sources */, EA5E305C295111050082B959 /* TileletViewController.swift in Sources */, EAD062A32A3913920015965D /* DropShawdowViewController.swift in Sources */, + EA6642972BD1B2E700D81DC4 /* ColorPickerView.swift in Sources */, EA0D1C312A673F3500E5C127 /* RadioButtonViewController.swift in Sources */, EAB5FEF32928153D00998C17 /* Helper.swift in Sources */, EA89204728B66CE2006B9984 /* KeyboardFrameChangeListener.swift in Sources */, @@ -692,7 +696,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 58; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = FCMA4QKS77; GENERATE_INFOPLIST_FILE = YES; @@ -727,7 +731,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 58; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = FCMA4QKS77; GENERATE_INFOPLIST_FILE = YES; diff --git a/VDSSample/Classes/ColorPickerView.swift b/VDSSample/Classes/ColorPickerView.swift new file mode 100644 index 0000000..a340698 --- /dev/null +++ b/VDSSample/Classes/ColorPickerView.swift @@ -0,0 +1,68 @@ +// +// ColorPickerView.swift +// VDSSample +// +// Created by Matt Bruce on 4/18/24. +// + +import Foundation +import UIKit +import VDS + +public class ColorPickerView: UIStackView { + public var pickerType: EnumType + public var selectedColor: UIColor? { + didSet { + selectedColorView.backgroundColor = selectedColor + } + } + + var selectedColorView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.widthAnchor.constraint(equalToConstant: 20).isActive = true + view.heightAnchor.constraint(equalToConstant: 20).isActive = true + return view + }() + + var button = Button().with { + $0.size = .small + $0.use = .secondary + $0.text = "Select" + } + + public init(with pickerType: EnumType, onClick: @escaping (ColorPickerView)->Void) { + self.pickerType = pickerType + super.init(frame: .zero) + setup() + button.onClick = { _ in onClick(self) } + } + + required init(coder: NSCoder) { + fatalError() + } + + private func setup() { + distribution = .fillEqually + alignment = .fill + spacing = 10 + + let indicatorWrapper = View() + indicatorWrapper.addSubview(selectedColorView) + indicatorWrapper.height(32) + indicatorWrapper.pinTop() + indicatorWrapper.pinLeading() + indicatorWrapper.pinBottom() + indicatorWrapper.pinTrailingGreaterThanOrEqualTo(anchor: indicatorWrapper.trailingAnchor) + + addArrangedSubview(indicatorWrapper) + let buttonWrapper = View() + buttonWrapper.addSubview(button) + buttonWrapper.height(32) + button.pinTop() + button.pinTrailing() + button.pinBottom() + button.pinLeadingGreaterThanOrEqualTo(anchor: buttonWrapper.leadingAnchor) + addArrangedSubview(buttonWrapper) + } +} diff --git a/VDSSample/ViewControllers/BadgeIndicatorViewController.swift b/VDSSample/ViewControllers/BadgeIndicatorViewController.swift index f3e57f0..69f662a 100644 --- a/VDSSample/ViewControllers/BadgeIndicatorViewController.swift +++ b/VDSSample/ViewControllers/BadgeIndicatorViewController.swift @@ -52,6 +52,7 @@ class BadgeIndicatorViewController: BaseViewController { var textField = NumericField() var leadingCharacterTextField = TextField() + var accessibilityTextField = TextField() var trailingTextField = TextField() var hideDotSwitch = Toggle() var hideBorderSwitch = Toggle() @@ -85,7 +86,8 @@ class BadgeIndicatorViewController: BaseViewController { addFormRow(label: "Border Light", view: borderColorLightPickerSelectorView) addFormRow(label: "Border Dark", view: borderColorDarkPickerSelectorView) addFormRow(label: "Size", view: textSizePickerSelectorView) - + addFormRow(label: "Accessiblity Text", view: accessibilityTextField) + dotForm.addFormRow(label: "Hide Dot", view: hideDotSwitch) dotForm.addFormRow(label: "Dot Size", view: dotSizeTextField) numberedForm.addFormRow(label: "Leading Character", view: leadingCharacterTextField) @@ -122,6 +124,11 @@ class BadgeIndicatorViewController: BaseViewController { self?.component.trailingText = text }.store(in: &subscribers) + accessibilityTextField.textPublisher + .sink { [weak self] text in + self?.component.accessibilityText = text + }.store(in: &subscribers) + heightTextField .numberPublisher .sink { [weak self] number in diff --git a/VDSSample/ViewControllers/BaseViewController.swift b/VDSSample/ViewControllers/BaseViewController.swift index 3c31212..631eeac 100644 --- a/VDSSample/ViewControllers/BaseViewController.swift +++ b/VDSSample/ViewControllers/BaseViewController.swift @@ -43,7 +43,7 @@ public class FormSection: UIStackView { } @discardableResult - open func addFormRow(label: String, view: UIView) -> UIView { + open func addFormRow(label: String, tooltip: Tooltip.TooltipModel? = nil, view: UIView) -> UIView { let formRow = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.alignment = .fill @@ -56,6 +56,10 @@ public class FormSection: UIStackView { $0.tag = 1 $0.text = label $0.textStyle = .bodyLarge + $0.numberOfLines = 0 + if let tooltip { + $0.addTooltip(tooltip) + } } formRow.addArrangedSubview(label) @@ -261,6 +265,21 @@ public class BaseViewController: UIViewController, Initable , loadCustomRotors() UIAccessibility.post(notification: .screenChanged, argument: component) } + + if component.canBecomeFirstResponder { + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) + tapGesture.cancelsTouchesInView = false // This allows the tap to pass through to other views. + view.addGestureRecognizer(tapGesture) + } + } + + @objc func dismissKeyboard(_ sender: UITapGestureRecognizer) { + let location = sender.location(in: self.view) + + // Check if the touch is outside the textView + if !component.frame.contains(location) { + component.resignFirstResponder() + } } func isViewHiddenByKeyboard(view: UIView, keyboardFrame: CGRect) -> Bool { @@ -318,10 +337,10 @@ public class BaseViewController: UIViewController, Initable , } @discardableResult - open func addFormRow(label: String, view: UIView) -> UIView { - return formStackView.addFormRow(label: label, view: view) + open func addFormRow(label: String, tooltip: Tooltip.TooltipModel? = nil, view: UIView) -> UIView { + return formStackView.addFormRow(label: label,tooltip: tooltip, view: view) } - + var activeTextField: UITextField? /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. diff --git a/VDSSample/ViewControllers/BreadcrumbsViewController.swift b/VDSSample/ViewControllers/BreadcrumbsViewController.swift index 1cee787..cecc9a4 100644 --- a/VDSSample/ViewControllers/BreadcrumbsViewController.swift +++ b/VDSSample/ViewControllers/BreadcrumbsViewController.swift @@ -90,3 +90,19 @@ class BreadcrumbsViewController: BaseViewController { } } + +extension BreadcrumbsViewController: ComponentSampleable { + static func makeSample() -> ComponentSample { + let component = Self.makeComponent() + component.breadcrumbModels = [ + .init(text: "Home"), + .init(text: "Support", enabeled: false), + .init(text: "Service & Apps"), + .init(text: "My Verizon"), + .init(text: "Bill"), + .init(text: "Mobile Billing & Payments"), + .init(text: "Billing statement FAQs", selected: true) + ] + return ComponentSample(component: component) + } +} diff --git a/VDSSample/ViewControllers/ButtonIconViewController.swift b/VDSSample/ViewControllers/ButtonIconViewController.swift index 5113cfc..1fae6a2 100644 --- a/VDSSample/ViewControllers/ButtonIconViewController.swift +++ b/VDSSample/ViewControllers/ButtonIconViewController.swift @@ -59,7 +59,7 @@ class ButtonIconViewController: BaseViewController { var selectableSwitch = Toggle() var badgeIndicatorSwitch = Toggle() var variantOneSwitch = Toggle() - + lazy var badgeIndicatorExpandDirectionPickerSelectorView = { PickerSelectorView(title: "right", picker: self.picker, @@ -75,6 +75,32 @@ class ButtonIconViewController: BaseViewController { var badgeIndicatorFormStackView = FormSection().with { $0.isHidden = true } + ///ColorPicker + var colorPickerType: ColorPickerType = .light + enum ColorPickerType { + case light, dark + } + + lazy var colorPicker: UIColorPickerViewController = { + let picker = UIColorPickerViewController() + picker.delegate = self + return picker + }() + + lazy var lightColorPicker: ColorPickerView = { + return .init(with: ColorPickerType.light) {[weak self] picker in + self?.colorPickerType = picker.pickerType + self?.selectedColorTapped(picker) + } + }() + + lazy var darkColorPicker: ColorPickerView = { + return .init(with: ColorPickerType.dark) {[weak self] picker in + self?.colorPickerType = picker.pickerType + self?.selectedColorTapped(picker) + } + }() + override func setupForm(){ super.setupForm() addFormRow(label: "Disabled", view: disabledSwitch) @@ -82,6 +108,8 @@ class ButtonIconViewController: BaseViewController { addFormRow(label: "Surface Type", view: surfaceTypePickerSelectorView) addFormRow(label: "Size", view: sizePickerSelectorView) addFormRow(label: "Kind", view: kindPickerSelectorView) + addFormRow(label: "Selected Light", view: lightColorPicker) + addFormRow(label: "Selected Dark", view: darkColorPicker) addFormRow(label: "Floating", view: floating) addFormRow(label: "Hide Border", view: hideBorder) addFormRow(label: "Fit To Icon", view: fitToIcon) @@ -153,6 +181,7 @@ class ButtonIconViewController: BaseViewController { let name = Icon.Name.addToFavorite component.iconName = name + component.onChange = { c in print("changed: \(c.isSelected)") } //setup UI surfacePickerSelectorView.text = component.surface.rawValue surfaceTypePickerSelectorView.text = component.surfaceType.rawValue @@ -212,12 +241,12 @@ class ButtonIconViewController: BaseViewController { func setBadgeIndicatorModel() { if variantOneSwitch.isOn { if badgeIndicatorSwitch.isOn { - component.badgeIndicatorModel = ButtonIcon.BadgeIndicatorModel(kind: BadgeIndicator.Kind.simple, size: BadgeIndicator.Size.small) + component.badgeIndicatorModel = ButtonIcon.BadgeIndicatorModel(kind: BadgeIndicator.Kind.simple, size: BadgeIndicator.Size.small, accessibilityText: "Custom Text would go here by the developer") } else { component.badgeIndicatorModel = nil } } else { - component.badgeIndicatorModel = ButtonIcon.BadgeIndicatorModel(kind: BadgeIndicator.Kind.numbered, expandDirection: badgeIndicatorExpandDirectionPickerSelectorView.selectedItem, size: BadgeIndicator.Size.small, maximumDigits: BadgeIndicator.MaximumDigits.two, number: 999) + component.badgeIndicatorModel = ButtonIcon.BadgeIndicatorModel(kind: BadgeIndicator.Kind.numbered, expandDirection: badgeIndicatorExpandDirectionPickerSelectorView.selectedItem, size: BadgeIndicator.Size.small, maximumDigits: BadgeIndicator.MaximumDigits.two, number: 999, accessibilityText: "Custom Text would go here by the developer for the 999") } } } @@ -233,7 +262,34 @@ extension ButtonIconViewController: ComponentSampleable { static func makeSample() -> ComponentSample { let component = Self.makeComponent() component.iconName = .addToFavorite + component.selectedIconName = .addedToFavorite + component.selectable = true + component.onChange = { c in print("changed: \(c.isSelected)") } component.size = .large return ComponentSample(component: component, trailingPinningType: .lessThanOrEqual) } } + +extension ButtonIconViewController: UIColorPickerViewControllerDelegate { + + func selectedColorTapped(_ picker: ColorPickerView) { + let selectedColor = picker.selectedColor + if let selectedColor { + colorPicker.selectedColor = selectedColor + } + present(colorPicker, animated: true) + } + + func colorPickerViewControllerDidFinish(_ viewController: UIColorPickerViewController) { + dismiss(animated: true) + } + + func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) { + let color = viewController.selectedColor + let selectedColorPickerView = colorPickerType == .dark ? darkColorPicker : lightColorPicker + selectedColorPickerView.selectedColor = color + if let selectedDarkColor = darkColorPicker.selectedColor, let selectedLightColor = lightColorPicker.selectedColor { + component.selectedIconColorConfiguration = .init(selectedLightColor, selectedDarkColor) + } + } +} diff --git a/VDSSample/ViewControllers/CarouselScrollbarViewConttroller.swift b/VDSSample/ViewControllers/CarouselScrollbarViewConttroller.swift index 99ca1ce..63b0da4 100644 --- a/VDSSample/ViewControllers/CarouselScrollbarViewConttroller.swift +++ b/VDSSample/ViewControllers/CarouselScrollbarViewConttroller.swift @@ -119,3 +119,12 @@ class CarouselScrollbarViewConttroller: BaseViewController { } } } + + +extension CarouselScrollbarViewConttroller: ComponentSampleable { + static func makeSample() -> ComponentSample { + let component = Self.makeComponent() + component.numberOfSlides = 4 + return ComponentSample(component: component) + } +} diff --git a/VDSSample/ViewControllers/DropShawdowViewController.swift b/VDSSample/ViewControllers/DropShawdowViewController.swift index ec8bfa7..9ef0b5d 100644 --- a/VDSSample/ViewControllers/DropShawdowViewController.swift +++ b/VDSSample/ViewControllers/DropShawdowViewController.swift @@ -34,9 +34,13 @@ class DropShadowViewController: BaseViewController { var componentWrapper: UIView! var componentConstraints: NSLayoutConstraint.Container! - var secondView = View() - var thirdView = View() + var secondView = ShadowView() + var thirdView = ShadowView() + var shadowViews: [ShadowView] { + [component, secondView, thirdView] + } + lazy var backgroundColorPickerSelectorView = { PickerSelectorView(title: "paletteWhite", picker: self.picker, @@ -125,8 +129,8 @@ class DropShadowViewController: BaseViewController { thirdView.width(viewSize).height(viewSize) componentWrapper.pinTop().pinLeading() - secondView.pinTop() - thirdView.pinLeading().pinBottom() + secondView.pinTop(VDSLayout.space2X) + thirdView.pinLeading(VDSLayout.space2X).pinBottom(VDSLayout.space2X) secondView.pinTrailingLessThanOrEqualTo(contentTopView.trailingAnchor) secondView.pinBottomLessThanOrEqualTo(contentTopView.bottomAnchor) @@ -194,7 +198,7 @@ class DropShadowViewController: BaseViewController { //shadow1 showShadow.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.showShadow = slider.isOn + self?.shadowViews.forEach { $0.showShadow = slider.isOn } self?.updateView() }).store(in: &subscribers) @@ -202,7 +206,7 @@ class DropShadowViewController: BaseViewController { opacityRange.minimumValue = 0.0 opacityRange.value = 1.0 opacityRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.opacityRange = CGFloat(slider.value) + self?.shadowViews.forEach { $0.opacityRange = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) @@ -210,7 +214,7 @@ class DropShadowViewController: BaseViewController { radiusRange.minimumValue = 0.0 radiusRange.value = 2.0 radiusRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.radiusRange = CGFloat(slider.value) + self?.shadowViews.forEach { $0.radiusRange = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) @@ -218,7 +222,7 @@ class DropShadowViewController: BaseViewController { offsetXRange.minimumValue = -20 offsetXRange.value = 2.0 offsetXRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.offsetXRange = CGFloat(slider.value) + self?.shadowViews.forEach { $0.offsetXRange = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) @@ -226,13 +230,13 @@ class DropShadowViewController: BaseViewController { offsetYRange.minimumValue = -20 offsetYRange.value = 2.0 offsetYRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.offsetYRange = CGFloat(slider.value) + self?.shadowViews.forEach { $0.offsetYRange = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) //shadow2 showShadow2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.showShadow2 = slider.isOn + self?.shadowViews.forEach { $0.showShadow2 = slider.isOn } self?.updateView() }).store(in: &subscribers) @@ -240,7 +244,7 @@ class DropShadowViewController: BaseViewController { opacityRange2.minimumValue = 0.0 opacityRange2.value = 1.0 opacityRange2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.opacityRange2 = CGFloat(slider.value) + self?.shadowViews.forEach { $0.opacityRange2 = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) @@ -248,7 +252,7 @@ class DropShadowViewController: BaseViewController { radiusRange2.minimumValue = 0.0 radiusRange2.value = 2.0 radiusRange2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.radiusRange2 = CGFloat(slider.value) + self?.shadowViews.forEach { $0.radiusRange2 = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) @@ -256,7 +260,7 @@ class DropShadowViewController: BaseViewController { offsetXRange2.minimumValue = -20 offsetXRange2.value = 2.0 offsetXRange2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.offsetXRange2 = CGFloat(slider.value) + self?.shadowViews.forEach { $0.offsetXRange2 = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) @@ -264,7 +268,7 @@ class DropShadowViewController: BaseViewController { offsetYRange2.minimumValue = -20 offsetYRange2.value = 2.0 offsetYRange2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.offsetYRange2 = CGFloat(slider.value) + self?.shadowViews.forEach { $0.offsetYRange2 = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) @@ -281,7 +285,7 @@ class DropShadowViewController: BaseViewController { viewRadiusRange.minimumValue = 0 viewRadiusRange.value = 8.0 viewRadiusRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in - self?.component.viewRadiusRange = CGFloat(slider.value) + self?.shadowViews.forEach { $0.viewRadiusRange = CGFloat(slider.value) } self?.updateView() }).store(in: &subscribers) @@ -310,8 +314,8 @@ class DropShadowViewController: BaseViewController { } override func updateView() { - secondView.backgroundColor = .red - thirdView.backgroundColor = .purple + secondView.viewLightColor = .paletteYellow53 + thirdView.viewLightColor = .paletteBlue46 } func setupPicker(){ @@ -322,20 +326,21 @@ class DropShadowViewController: BaseViewController { } dropShadowDarkColorPickerSelectorView.onPickerDidSelect = { [weak self] item in - self?.component.shadowDarkColor = item + self?.shadowViews.forEach { $0.shadowDarkColor = item } } dropShadowLightColorPickerSelectorView.onPickerDidSelect = { [weak self] item in - self?.component.shadowLightColor = item + self?.shadowViews.forEach { $0.shadowLightColor = item } } dropShadow2DarkColorPickerSelectorView.onPickerDidSelect = { [weak self] item in - self?.component.shadowDarkColor2 = item + self?.shadowViews.forEach { $0.shadowDarkColor2 = item } } dropShadow2LightColorPickerSelectorView.onPickerDidSelect = { [weak self] item in - self?.component.shadowLightColor2 = item + self?.shadowViews.forEach { $0.shadowLightColor2 = item } } + viewLightColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.viewLightColor = item } @@ -353,7 +358,6 @@ public class ShadowView: View { public var viewRadiusRange: CGFloat = 8.0 { didSet { setNeedsUpdate() }} - private var shadowLayer1: CALayer = CALayer() public var showShadow: Bool = true { didSet { setNeedsUpdate() }} public var opacityRange: CGFloat = 1.0 { didSet { setNeedsUpdate() }} public var offsetXRange: CGFloat = 2.0 { didSet { setNeedsUpdate() }} @@ -362,7 +366,6 @@ public class ShadowView: View { public var shadowLightColor: UIColor.VDSColor = .backgroundPrimaryDark { didSet { setNeedsUpdate() }} public var shadowDarkColor: UIColor.VDSColor = .backgroundPrimaryLight { didSet { setNeedsUpdate() }} - private var shadowLayer2: CALayer = CALayer() public var showShadow2: Bool = false { didSet { setNeedsUpdate() }} public var opacityRange2: CGFloat = 1.0 { didSet { setNeedsUpdate() }} public var offsetXRange2: CGFloat = 2.0 { didSet { setNeedsUpdate() }} @@ -376,46 +379,86 @@ public class ShadowView: View { width(constant: 100) height(constant: 100) - // Add shadow layers as sublayers of the view's layer - layer.insertSublayer(shadowLayer1, at: 0) - layer.insertSublayer(shadowLayer2, at: 0) } public override func updateView() { super.updateView() let viewColor = SurfaceColorConfiguration(viewLightColor.uiColor, viewDarkColor.uiColor).getColor(surface) backgroundColor = viewColor - shadowLayer1.backgroundColor = viewColor.cgColor - shadowLayer2.backgroundColor = viewColor.cgColor - shadowLayer1.isHidden = !showShadow - shadowLayer2.isHidden = !showShadow2 + setNeedsLayout() layoutIfNeeded() } + public override var backgroundColor: UIColor? { + didSet { + print("backgroundColor: \(backgroundColor?.hexString ?? "None")") + } + } public override func layoutSubviews() { super.layoutSubviews() + + layer.cornerRadius = CGFloat(viewRadiusRange) let dropshadowColor = SurfaceColorConfiguration(shadowLightColor.uiColor, shadowDarkColor.uiColor).getColor(surface) let dropshadowColor2 = SurfaceColorConfiguration(shadowLightColor2.uiColor, shadowDarkColor2.uiColor).getColor(surface) - layer.cornerRadius = CGFloat(viewRadiusRange) - layer.masksToBounds = false + var shadowConfigs = [DropShadowConfiguration]() // Update shadow layers frames to match the view's bounds - shadowLayer1.frame = bounds - shadowLayer2.frame = bounds - - shadowLayer1.cornerRadius = CGFloat(viewRadiusRange) - shadowLayer1.shadowColor = dropshadowColor.cgColor - shadowLayer1.shadowOpacity = Float(opacityRange) - shadowLayer1.shadowOffset = .init(width: CGFloat(offsetXRange), height: CGFloat(offsetYRange)) - shadowLayer1.shadowRadius = CGFloat(radiusRange) + if showShadow { + let shadow1Config = VDS.DropShadowConfiguration().with { + $0.shadowRadiusConfiguration = .init(viewRadiusRange, .zero) + $0.shadowColorConfiguration = SurfaceColorConfiguration(dropshadowColor, dropshadowColor).eraseToAnyColorable() + $0.shadowOpacityConfiguration = .init(opacityRange, .zero) + $0.shadowOffsetConfiguration = .init(.init(width: offsetXRange, height: offsetYRange), .zero) + $0.shadowRadiusConfiguration = .init(radiusRange, .zero) + } + shadowConfigs.append(shadow1Config) + } - shadowLayer2.cornerRadius = CGFloat(viewRadiusRange) - shadowLayer2.shadowColor = dropshadowColor2.cgColor - shadowLayer2.shadowOpacity = Float(opacityRange2) - shadowLayer2.shadowOffset = .init(width: CGFloat(offsetXRange2), height: CGFloat(offsetYRange2)) - shadowLayer2.shadowRadius = CGFloat(radiusRange2) + if showShadow2 { + let shadow2Config = VDS.DropShadowConfiguration().with { + $0.shadowRadiusConfiguration = .init(viewRadiusRange, .zero) + $0.shadowColorConfiguration = SurfaceColorConfiguration(dropshadowColor2, dropshadowColor2).eraseToAnyColorable() + $0.shadowOpacityConfiguration = .init(opacityRange2, .zero) + $0.shadowOffsetConfiguration = .init(.init(width: offsetXRange2, height: offsetYRange2), .zero) + $0.shadowRadiusConfiguration = .init(radiusRange2, .zero) + } + shadowConfigs.append(shadow2Config) + } + + if shadowConfigs.count > 0 { + addDropShadows(shadowConfigs) + } else { + removeDropShadows() + } + + } +} + +extension ViewProtocol where Self: UIView { + private func createShadowLayer() -> CALayer { + let shadowLayer = CALayer() + shadowLayer.backgroundColor = UIColor.clear.cgColor + shadowLayer.frame = bounds + return shadowLayer + } + + func addCustomShadow(config: DropShadowConfiguration) { + let shadowLayer = createShadowLayer() +// shadowLayer.shadowColor = config.shadowColorConfiguration.getColor(self).cgColor +// shadowLayer.shadowOpacity = config.shadowOpacityConfiguration.value(for: self) +// shadowLayer.shadowOffset = offset +// shadowLayer.shadowRadius = radius + layer.insertSublayer(shadowLayer, at: 0) + } + + func removeAllCustomShadows() { + layer.sublayers?.forEach { sublayer in + if sublayer.shadowOpacity > 0 && sublayer.backgroundColor == UIColor.clear.cgColor { + sublayer.removeFromSuperlayer() + } + } } } diff --git a/VDSSample/ViewControllers/DropdownSelectViewController.swift b/VDSSample/ViewControllers/DropdownSelectViewController.swift index 177aa4c..6fcc338 100644 --- a/VDSSample/ViewControllers/DropdownSelectViewController.swift +++ b/VDSSample/ViewControllers/DropdownSelectViewController.swift @@ -10,6 +10,12 @@ import VDS class DropdownSelectViewController: BaseViewController { + lazy var helperTextPlacementPickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: InputField.HelperTextPlacement.allCases) + }() + var disabledSwitch = Toggle() var requiredSwitch = Toggle() var labelTextField = TextField() @@ -21,6 +27,7 @@ class DropdownSelectViewController: BaseViewController { var errorSwitch = Toggle() var tooltipTitleTextField = TextField() var tooltipContentTextField = TextField() + var widthTextField = NumericField() var optionsSwitch = Toggle() var moreOptions: [DropdownSelect.DropdownOptionModel] = [ .init(text: "Alabama"), @@ -60,12 +67,14 @@ class DropdownSelectViewController: BaseViewController { addFormRow(label: "Disabled", view: disabledSwitch) addFormRow(label: "Required", view: requiredSwitch) addFormRow(label: "Label Text", view: labelTextField) + addFormRow(label: "Helper Text Placement", view: helperTextPlacementPickerSelectorView) addFormRow(label: "Helper Text", view: helperTextField) addFormRow(label: "Inline Label", view: .makeWrapper(for: inlineLabelSwitch)) addFormRow(label: "Readonly", view: readonlySwitch) addFormRow(label: "Transparent Background", view: transparentBgSwitch) addFormRow(label: "Error", view: .makeWrapper(for: errorSwitch)) addFormRow(label: "Error Text", view: errorTextField) + addFormRow(label: "Width", view: widthTextField) addFormRow(label: "ToolTip Title", view: tooltipTitleTextField) addFormRow(label: "ToolTip Content", view: tooltipContentTextField) addFormRow(label: "More Options", view: optionsSwitch) @@ -75,7 +84,7 @@ class DropdownSelectViewController: BaseViewController { } requiredSwitch.onChange = { [weak self] sender in - self?.component.required = sender.isOn + self?.component.isRequired = sender.isOn } optionsSwitch.onChange = { [weak self] sender in @@ -84,7 +93,7 @@ class DropdownSelectViewController: BaseViewController { } readonlySwitch.onChange = { [weak self] sender in - self?.component.readOnly = sender.isOn + self?.component.isReadOnly = sender.isOn } transparentBgSwitch.onChange = { [weak self] sender in @@ -119,6 +128,12 @@ class DropdownSelectViewController: BaseViewController { self?.component.errorText = text }.store(in: &subscribers) + widthTextField + .numberPublisher + .sink { [weak self] number in + self?.component.width = number?.cgFloatValue + }.store(in: &subscribers) + tooltipTitleTextField .textPublisher .sink { [weak self] text in @@ -158,9 +173,10 @@ class DropdownSelectViewController: BaseViewController { //setup UI disabledSwitch.isOn = !component.isEnabled - requiredSwitch.isOn = component.required + requiredSwitch.isOn = component.isRequired surfacePickerSelectorView.text = component.surface.rawValue labelTextField.text = component.labelText + helperTextPlacementPickerSelectorView.text = component.helperTextPlacement.rawValue helperTextField.text = component.helperText readonlySwitch.isOn = false transparentBgSwitch.isOn = false @@ -176,6 +192,11 @@ class DropdownSelectViewController: BaseViewController { self?.component.surface = item self?.contentTopView.backgroundColor = item.color } + + helperTextPlacementPickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.helperTextPlacement = item + } + } func updateTooltip() { @@ -186,3 +207,22 @@ class DropdownSelectViewController: BaseViewController { content: content) : nil } } + +extension DropdownSelectViewController: ComponentSampleable { + static func makeSample() -> ComponentSample { + let component = Self.makeComponent() + component.labelText = "Street Address" + component.helperText = "For example: 123 Verizon St" + component.errorText = "Enter a valid address." + component.tooltipModel = .init(title: "Check the formatting of your address", content:"House/Building number then street name") + component.options = [ + .init(text: "Alabama"), + .init(text: "Alaska"), + .init(text: "Arizona"), + .init(text: "Arkansas") + ] + return ComponentSample(component: component) + } +} + + diff --git a/VDSSample/ViewControllers/InputFieldViewController.swift b/VDSSample/ViewControllers/InputFieldViewController.swift index 61d5350..9ca4875 100644 --- a/VDSSample/ViewControllers/InputFieldViewController.swift +++ b/VDSSample/ViewControllers/InputFieldViewController.swift @@ -19,6 +19,12 @@ class InputFieldViewController: BaseViewController { items: InputField.HelperTextPlacement.allCases) }() + lazy var inputTypePickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: InputField.FieldType.allCases) + }() + var disabledSwitch = Toggle() var requiredSwitch = Toggle() var labelTextField = TextField() @@ -31,6 +37,52 @@ class InputFieldViewController: BaseViewController { var tooltipTitleTextField = TextField() var tooltipContentTextField = TextField() + //FieldType sections + + //password + var hidePasswordButtonTextField = TextField() + var showPasswordButtonTextField = TextField() + lazy var passwordSection = FormSection().with { + $0.title = "Password Settings" + $0.addFormRow(label: "Hide Button", view: hidePasswordButtonTextField) + $0.addFormRow(label: "Show Button", view: showPasswordButtonTextField) + $0.isHidden = true + } + + //date + lazy var dateFormatPickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: InputField.DateFormat.allCases) + }() + + lazy var dateSection = FormSection().with { + $0.title = "Date Settings" + $0.addFormRow(label: "Date Format", view: dateFormatPickerSelectorView) + $0.isHidden = true + } + + //inlineAction + var inlineActionTextField = TextField() + lazy var inlineActionSection = FormSection().with { + $0.title = "inlineAction Settings" + $0.addFormRow(label: "Action Text", view: inlineActionTextField) + $0.isHidden = true + } + + //securityCode + lazy var cardTypePickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: InputField.CreditCardType.allCases) + }() + + lazy var securityCodeSection = FormSection().with { + $0.title = "Security Code Settings" + $0.addFormRow(label: "Card Type", view: cardTypePickerSelectorView) + $0.isHidden = true + } + override func viewDidLoad() { super.viewDidLoad() addContentTopView(view: component) @@ -40,22 +92,40 @@ class InputFieldViewController: BaseViewController { override func setupForm(){ super.setupForm() - addFormRow(label: "Disabled", view: disabledSwitch) - addFormRow(label: "Required", view: requiredSwitch) - addFormRow(label: "Surface", view: surfacePickerSelectorView) - addFormRow(label: "Label Text", view: labelTextField) - addFormRow(label: "Helper Text Placement", view: helperTextPlacementPickerSelectorView) - addFormRow(label: "Helper Text", view: helperTextField) - addFormRow(label: "Error", view: showErrorSwitch) - addFormRow(label: "Error Text", view: errorTextField) - addFormRow(label: "Success", view: showSuccessSwitch) - addFormRow(label: "Success Text", view: successTextField) - addFormRow(label: "Width", view: widthTextField) - addFormRow(label: "ToolTip Title", view: tooltipTitleTextField) - addFormRow(label: "ToolTip Content", view: tooltipContentTextField) + + let fieldType = FormSection().with { + $0.title = "Field Type Settings" + $0.addFormRow(label: "Field Type", view: inputTypePickerSelectorView) + } + + let general = FormSection().with { + $0.title = "\n\nGeneral Settings" + } + + general.addFormRow(label: "Disabled", view: disabledSwitch) + general.addFormRow(label: "Required", view: requiredSwitch) + general.addFormRow(label: "Surface", view: surfacePickerSelectorView) + general.addFormRow(label: "Label Text", view: labelTextField) + general.addFormRow(label: "Helper Text Placement", view: helperTextPlacementPickerSelectorView) + general.addFormRow(label: "Helper Text", view: helperTextField) + general.addFormRow(label: "Error", view: showErrorSwitch) + general.addFormRow(label: "Error Text", view: errorTextField) + general.addFormRow(label: "Success", view: showSuccessSwitch) + general.addFormRow(label: "Success Text", view: successTextField) + general.addFormRow(label: "Width", view: widthTextField) + general.addFormRow(label: "ToolTip Title", view: tooltipTitleTextField) + general.addFormRow(label: "ToolTip Content", view: tooltipContentTextField) + + append(section: fieldType) + append(section: passwordSection) + append(section: dateSection) + append(section: inlineActionSection) + append(section: securityCodeSection) + append(section: general) + requiredSwitch.onChange = { [weak self] sender in - self?.component.required = sender.isOn + self?.component.isRequired = sender.isOn } showErrorSwitch.onChange = { [weak self] sender in @@ -114,17 +184,42 @@ class InputFieldViewController: BaseViewController { self?.updateTooltip() }.store(in: &subscribers) + //field types + //password + hidePasswordButtonTextField + .textPublisher + .sink { [weak self] text in + self?.component.hidePasswordButtonText = text + }.store(in: &subscribers) + + showPasswordButtonTextField + .textPublisher + .sink { [weak self] text in + self?.component.showPasswordButtonText = text + }.store(in: &subscribers) + + //inlineAction + inlineActionTextField + .textPublisher + .sink { [weak self] text in + if !text.isEmpty { + self?.component.actionTextLinkModel = .init(text: text, onClick: { inputField in + var value = inputField.value ?? "" + value = !value.isEmpty ? value : "nil" + self?.present(UIAlertController(title: "inlineAction", message: "Clicked and you get the value: \(value)", preferredStyle: .alert).with{ $0.addAction(.init(title: "OK", style: .default)) }, animated: true) + }) + } else { + self?.component.actionTextLinkModel = nil + } + }.store(in: &subscribers) } func setupModel() { component.fieldType = .text - component.width = 328 - component.text = "Starting Text" component.labelText = "Street Address" component.helperText = "For example: 123 Verizon St" component.errorText = "Enter a valid address." component.successText = "Good job entering a valid address!" - component.tooltipModel = .init(title: "Check the formatting of your address", content:"House/Building number then street name") component.onChange = { component in if let text = component.value { @@ -137,8 +232,10 @@ class InputFieldViewController: BaseViewController { //setup UI surfacePickerSelectorView.text = component.surface.rawValue helperTextPlacementPickerSelectorView.text = component.helperTextPlacement.rawValue + dateFormatPickerSelectorView.text = component.dateFormat.rawValue + inputTypePickerSelectorView.text = component.fieldType.rawValue disabledSwitch.isOn = !component.isEnabled - requiredSwitch.isOn = component.required + requiredSwitch.isOn = component.isRequired labelTextField.text = component.labelText helperTextField.text = component.helperText showErrorSwitch.isOn = component.showError @@ -162,6 +259,21 @@ class InputFieldViewController: BaseViewController { helperTextPlacementPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.helperTextPlacement = item } + + inputTypePickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.fieldType = item + self?.component.text = "" + self?.updateFormSections() + } + + dateFormatPickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.dateFormat = item + self?.updateFormSections() + } + + cardTypePickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.cardType = item + } } func updateTooltip() { @@ -171,6 +283,35 @@ class InputFieldViewController: BaseViewController { component.tooltipModel = !title.isEmpty || !content.isEmpty ? .init(title: title, content: content) : nil } + + func updateFormSections() { + [passwordSection, dateSection, inlineActionSection, securityCodeSection].forEach { $0.isHidden = true } + //reset other fields + component.actionTextLinkModel = nil + component.tooltipModel = nil + component.cardType = .generic + tooltipTitleTextField.text = nil + tooltipContentTextField.text = nil + dateFormatPickerSelectorView.text = component.dateFormat.rawValue + cardTypePickerSelectorView.text = component.cardType.rawValue + switch component.fieldType { + case .inlineAction: + inlineActionTextField.text = nil + inlineActionSection.isHidden = false + + case .password: + passwordSection.isHidden = false + + case .date: + dateSection.isHidden = false + + case .securityCode: + securityCodeSection.isHidden = false + + default: + break + } + } } diff --git a/VDSSample/ViewControllers/MenuViewController.swift b/VDSSample/ViewControllers/MenuViewController.swift index e55c22c..7600428 100644 --- a/VDSSample/ViewControllers/MenuViewController.swift +++ b/VDSSample/ViewControllers/MenuViewController.swift @@ -81,7 +81,7 @@ class MenuViewController: UITableViewController, TooltipLaunchable { MenuComponent(title: "DatePicker", completed: false, viewController: DatePickerViewController.self), MenuComponent(title: "DropdownSelect", completed: true, viewController: DropdownSelectViewController.self), MenuComponent(title: "Icon", completed: true, viewController: IconViewController.self), - MenuComponent(title: "InputField", completed: false, viewController: InputFieldViewController.self), + MenuComponent(title: "InputField", completed: true, viewController: InputFieldViewController.self), MenuComponent(title: "Label", completed: true, viewController: LabelViewController.self), MenuComponent(title: "Line", completed: true, viewController: LineViewController.self), MenuComponent(title: "Loader", completed: true, viewController: LoaderViewController.self), diff --git a/VDSSample/ViewControllers/PaginationViewController.swift b/VDSSample/ViewControllers/PaginationViewController.swift index 47a5807..920c4a9 100644 --- a/VDSSample/ViewControllers/PaginationViewController.swift +++ b/VDSSample/ViewControllers/PaginationViewController.swift @@ -46,3 +46,11 @@ final class PaginationViewController: BaseViewController { }.store(in: &subscribers) } } + +extension PaginationViewController: ComponentSampleable { + static func makeSample() -> ComponentSample { + let component = Self.makeComponent() + component.total = 10 + return ComponentSample(component: component) + } +} diff --git a/VDSSample/ViewControllers/TableViewTestController.swift b/VDSSample/ViewControllers/TableViewTestController.swift index b7b1ddd..8de4507 100644 --- a/VDSSample/ViewControllers/TableViewTestController.swift +++ b/VDSSample/ViewControllers/TableViewTestController.swift @@ -172,30 +172,8 @@ public class TableViewTestController: UIViewController, Initable, Surfaceable { } var items: [MenuComponent] { - all - } - - var all: [MenuComponent] { MenuViewController.items - } - - var batch1: [MenuComponent] { - [ - MenuComponent(title: "Badge", completed: true, viewController: BadgeViewController.self), - MenuComponent(title: "Button", completed: true, viewController: ButtonViewController.self), - MenuComponent(title: "ButtonGroup", completed: true, viewController: ButtonGroupViewController.self), - MenuComponent(title: "Icon", completed: true, viewController: IconViewController.self), - MenuComponent(title: "Label", completed: true, viewController: LabelViewController.self), - MenuComponent(title: "Line", completed: true, viewController: LineViewController.self), - MenuComponent(title: "Loader", completed: true, viewController: LoaderViewController.self), - MenuComponent(title: "Tabs", completed: true, viewController: TabsViewController.self), - MenuComponent(title: "TextLink", completed: true, viewController: TextLinkViewController.self), - MenuComponent(title: "TextLinkCaret", completed: true, viewController: TextLinkCaretViewController.self), - MenuComponent(title: "TitleLockup", completed: true, viewController: TitleLockupViewController.self), - MenuComponent(title: "Tooltip", completed: true, viewController: TooltipViewController.self), - MenuComponent(title: "TrailingTooltip", completed: true, viewController: TrailingTooltipLabelViewController.self), - ] - } + } } extension TableViewTestController : UITableViewDelegate, UITableViewDataSource { diff --git a/VDSSample/ViewControllers/TextAreaViewController.swift b/VDSSample/ViewControllers/TextAreaViewController.swift index 9769795..6559a2e 100644 --- a/VDSSample/ViewControllers/TextAreaViewController.swift +++ b/VDSSample/ViewControllers/TextAreaViewController.swift @@ -55,7 +55,7 @@ class TextAreaViewController: BaseViewController