From a6f03e3e1e449b5d2867cdc445983adc162ec722 Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 2 Apr 2024 18:20:02 +0530 Subject: [PATCH] Digital ACT-191 ONEAPP-7135 story: using tooltip model --- .../DropdownSelect/DropdownSelect.swift | 191 +++++++----------- 1 file changed, 77 insertions(+), 114 deletions(-) diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index d7613f94..826f768e 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -34,69 +34,48 @@ open class DropdownSelect: Control { // MARK: - Public Properties //-------------------------------------------------- - ///Boolean value that determines if component should show the error state/error message. + /// Boolean value that determines if component should show the error state/error message. open var error: Bool = false { didSet { setNeedsUpdate() }} - + /// Message displayed when there is an error. open var errorText: String? { didSet { setNeedsUpdate() }} - + /// If provided, will be used as text for the helper label. open var helperText: String? { didSet { setNeedsUpdate() }} - - /// used if the component is enabled or not. + + /// Used if the component is enabled or not. open override var isEnabled: Bool { didSet { setNeedsUpdate() }} - + /// If true, the label will be displayed inside the dropdown container. Otherwise, the label will be above the dropdown container like a normal text input. open var inlineLabel: Bool = false { didSet { setNeedsUpdate() }} - + /// If provided, will be used as context for the label on the input field. open var label: String? { didSet { setNeedsUpdate() }} /// Not allowed the user interaction to select/change input if it is true. open var readOnly: Bool = false { didSet { setNeedsUpdate() }} - + /// Used to show optional indicator for the label. open var required: Bool = false { didSet { setNeedsUpdate() }} - + /// Allows unique ID to be passed to the element. open var selectId: String? { didSet { setNeedsUpdate() }} - - // TO DO: either have model or individual title and content. + /// Config object for tooltip option, is optional. open var tooltipModel: Tooltip.TooltipModel? { didSet { setNeedsUpdate() } } - - /// Used to set tooltip title. - open var tooltipTitle: String { - get { return _tooltipTitle } - set { - _tooltipTitle = newValue - updateTooltip() - setNeedsUpdate() - } - } - /// Used to set tooltip content. - open var tooltipContent: String { - get { return _tooltipContent } - set { - _tooltipContent = newValue - updateTooltip() - setNeedsUpdate() - } - } - /// If provided, will render with trnasparent background. open var transparentBackground: Bool = false { didSet { setNeedsUpdate() }} /// Used to set width for the Dropdown Select. open var width: Int? { didSet { setNeedsUpdate() }} - - // TO DO: create model for options + + /// TO DO: create model for options open var options: [String]? { didSet { setNeedsUpdate() }} - ///Boolean or a Function that returns a boolean value that determines if component should show the error state/error message.Functon receives the 'event' object on input change. + /// Boolean value that determines if component should show the error state/error message. Functon receives the 'event' object on input change. open var showError: Bool = false { didSet { setNeedsUpdate() }} - + open override var state: UIControl.State { get { var state = super.state @@ -110,18 +89,14 @@ open class DropdownSelect: Control { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var _tooltipTitle: String = "" - - internal var _tooltipContent: String = "" - internal var minWidthDefault = 66.0 internal var minWidthInlineLabel = 102.0 - + var stackView: UIStackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .vertical } - + private var eyebrowLabel = TrailingTooltipLabel().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.labelTextAlignment = .left @@ -131,7 +106,7 @@ open class DropdownSelect: Control { var container: UIView = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } - + var containerStack: UIStackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal @@ -143,7 +118,7 @@ open class DropdownSelect: Control { $0.tintColor = UIColor.clear $0.font = TextStyle.bodyLarge.font } - + private var inlineDisplayLabel = Label().with { $0.textAlignment = .left $0.textStyle = .boldBodyLarge @@ -155,12 +130,12 @@ open class DropdownSelect: Control { $0.textAlignment = .left $0.textStyle = .bodyLarge } - + private var icon: Icon = Icon().with { $0.size = .medium $0.name = Icon.Name(name: "down-caret") } - + private var errorLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textAlignment = .left @@ -172,7 +147,7 @@ open class DropdownSelect: Control { $0.textAlignment = .left $0.textStyle = .bodySmall } - + private var optionsPicker = UIPickerView() //-------------------------------------------------- @@ -185,7 +160,7 @@ open class DropdownSelect: Control { // MARK: - Configuration Properties //-------------------------------------------------- internal var containerSize: CGSize { CGSize(width: 45, height: 44) } - + /// Color configuration for error icon. internal let primaryColorConfig = ViewColorConfiguration().with { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) @@ -196,13 +171,13 @@ open class DropdownSelect: Control { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) $0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark, forDisabled: false) } - + internal var backgroundColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .normal) $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) } - + internal var containerBorderColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOnlight, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) @@ -210,16 +185,15 @@ open class DropdownSelect: Control { } //-------------------------------------------------- - // MARK: - Lifecycle + // 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() - + isAccessibilityElement = true accessibilityLabel = "Dropdown Select" - + addSubview(stackView) container.addSubview(containerStack) @@ -227,6 +201,7 @@ open class DropdownSelect: Control { dropdownField.width(0) + // container stack let spacing = VDSFormControls.spaceInset containerStack.pinToSuperView(.init(top: spacing, left: spacing, bottom: spacing, right: spacing)) containerStack.addArrangedSubview(dropdownField) @@ -237,12 +212,13 @@ open class DropdownSelect: Control { containerStack.setCustomSpacing(0, after: dropdownField) containerStack.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: inlineDisplayLabel) containerStack.setCustomSpacing(VDSLayout.Spacing.space3X.value, after: selectedOptionLabel) - + + // component stack stackView.addArrangedSubview(eyebrowLabel) stackView.addArrangedSubview(container) stackView.addArrangedSubview(errorLabel) stackView.addArrangedSubview(helperLabel) - + stackView.setCustomSpacing(4, after: eyebrowLabel) stackView.setCustomSpacing(8, after: container) stackView.setCustomSpacing(8, after: errorLabel) @@ -250,10 +226,10 @@ open class DropdownSelect: Control { stackView.pinToSuperView() inlineWidthConstraint = inlineDisplayLabel.widthAnchor.constraint(equalToConstant: 0) inlineWidthConstraint?.isActive = true - + widthConstraint = stackView.widthAnchor.constraint(greaterThanOrEqualToConstant: minWidthDefault) widthConstraint?.isActive = true - + eyebrowLabel.textColorConfiguration = primaryColorConfig.eraseToAnyColorable() errorLabel.textColorConfiguration = primaryColorConfig.eraseToAnyColorable() helperLabel.textColorConfiguration = secondaryColorConfig.eraseToAnyColorable() @@ -261,7 +237,7 @@ open class DropdownSelect: Control { optionsPicker.delegate = self optionsPicker.dataSource = self - + optionsPicker.isHidden = true dropdownField.inputView = optionsPicker @@ -272,40 +248,7 @@ open class DropdownSelect: Control { }.store(in: &subscribers) } - open override func reset() { - super.reset() - - eyebrowLabel.reset() - inlineDisplayLabel.reset() - selectedOptionLabel.reset() - errorLabel.reset() - helperLabel.reset() - - eyebrowLabel.labelTextAlignment = .left - eyebrowLabel.labelTextStyle = .bodySmall - inlineDisplayLabel.textStyle = .boldBodyLarge - inlineDisplayLabel.textAlignment = .left - selectedOptionLabel.textStyle = .bodyLarge - selectedOptionLabel.textAlignment = .left - errorLabel.textAlignment = .left - errorLabel.textStyle = .bodySmall - helperLabel.textAlignment = .left - helperLabel.textStyle = .bodySmall - tooltipModel = nil - tooltipTitle = "" - tooltipContent = "" - label = nil - errorText = nil - error = false - isEnabled = false - readOnly = false - inlineLabel = false - helperText = nil - transparentBackground = false - required = false - options = [] - } - + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { container.backgroundColor = backgroundColorConfiguration.getColor(self) container.layer.borderColor = containerBorderColorConfiguration.getColor(self).cgColor @@ -331,13 +274,46 @@ open class DropdownSelect: Control { } } + /// Resets to default settings. + open override func reset() { + super.reset() + + eyebrowLabel.reset() + inlineDisplayLabel.reset() + selectedOptionLabel.reset() + errorLabel.reset() + helperLabel.reset() + + eyebrowLabel.labelTextStyle = .bodySmall + inlineDisplayLabel.textStyle = .boldBodyLarge + selectedOptionLabel.textStyle = .bodyLarge + errorLabel.textStyle = .bodySmall + helperLabel.textStyle = .bodySmall + tooltipModel = nil + label = nil + errorText = nil + error = false + isEnabled = false + readOnly = false + inlineLabel = false + helperText = nil + transparentBackground = false + required = false + options = [] + } + + //-------------------------------------------------- + // MARK: - Public Methods + //-------------------------------------------------- + open func updateTitleLabel() { - + + //update the local vars for the label since we no long have a model var attributes: [any LabelAttributeModel] = [] var updatedLabelText = label updatedLabelText = inlineLabel ? "" : updatedLabelText - + if let oldText = updatedLabelText, !required, !oldText.hasSuffix("Optional") { let optionColorAttr = ColorLabelAttribute(location: oldText.count + 2, length: 8, @@ -347,30 +323,24 @@ open class DropdownSelect: Control { attributes.append(optionColorAttr) } -// updateTooltip() if let tooltipModel { attributes.append(TooltipLabelAttribute(surface: surface, model: tooltipModel, presenter: self)) } - + eyebrowLabel.labelText = updatedLabelText eyebrowLabel.labelAttributes = attributes eyebrowLabel.tooltipModel = tooltipModel eyebrowLabel.surface = surface eyebrowLabel.isEnabled = isEnabled - } - //-------------------------------------------------- - // MARK: - Public Methods - //-------------------------------------------------- - open func updateInlineLabel() { - + ///Minimum width with inline text as per design widthConstraint?.constant = inlineLabel ? minWidthInlineLabel : minWidthDefault widthConstraint?.isActive = true - -// inlineDisplayLabel.text = inlineLabel ? (label!.isEmpty ? ((label ?? "") + ":") : label) : "" + + // inlineDisplayLabel.text = inlineLabel ? (label!.isEmpty ? ((label ?? "") + ":") : label) : "" inlineDisplayLabel.text = inlineLabel ? label : "" inlineDisplayLabel.surface = surface inlineWidthConstraint?.constant = inlineDisplayLabel.intrinsicContentSize.width @@ -381,7 +351,7 @@ open class DropdownSelect: Control { selectedOptionLabel.text = text ?? "" } - open func updateErrorLabel(){ + open func updateErrorLabel() { if showError, let errorText { errorLabel.text = errorText errorLabel.surface = surface @@ -398,8 +368,7 @@ open class DropdownSelect: Control { } } - open func updateHelperLabel(){ - + open func updateHelperLabel() { if let helperText { helperLabel.text = helperText helperLabel.surface = surface @@ -426,18 +395,12 @@ open class DropdownSelect: Control { let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(pickerDoneClicked)) let flexibleSpaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) - + inputToolbar.setItems([flexibleSpaceButton, doneButton], animated: false) inputToolbar.isUserInteractionEnabled = true inputToolbar.sizeToFit() return inputToolbar } - - func updateTooltip() { - self.tooltipModel = .init(title: tooltipTitle, content: tooltipContent) - } - - } extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {