Merge branch 'mbruce/modal' into 'develop'
removed width/height contraints in dialog and pushed down to the viewcontroller. See merge request BPHV_MIPS/vds_ios!309
This commit is contained in:
commit
92a80b6496
@ -10,6 +10,10 @@
|
|||||||
180636C72C29B0A400C92D86 /* InputStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 180636C62C29B0A400C92D86 /* InputStepper.swift */; };
|
180636C72C29B0A400C92D86 /* InputStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 180636C62C29B0A400C92D86 /* InputStepper.swift */; };
|
||||||
180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */; };
|
180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */; };
|
||||||
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */; };
|
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */; };
|
||||||
|
1818D04D2C9BD2170053E73C /* ModalDialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1818D04C2C9BD2170053E73C /* ModalDialogViewController.swift */; };
|
||||||
|
1818D04F2C9BD3F60053E73C /* ModalDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1818D04E2C9BD3F60053E73C /* ModalDialog.swift */; };
|
||||||
|
1818D0512C9BD4090053E73C /* ModalLaunchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1818D0502C9BD4090053E73C /* ModalLaunchable.swift */; };
|
||||||
|
1818D0532C9BD47C0053E73C /* ModalModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1818D0522C9BD47C0053E73C /* ModalModel.swift */; };
|
||||||
1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; };
|
1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; };
|
||||||
183B16F32C78CF7C00BA6A10 /* CarouselSlotCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */; };
|
183B16F32C78CF7C00BA6A10 /* CarouselSlotCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */; };
|
||||||
183B16F72C80B32200BA6A10 /* FootnoteGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */; };
|
183B16F72C80B32200BA6A10 /* FootnoteGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */; };
|
||||||
@ -30,6 +34,8 @@
|
|||||||
18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */; };
|
18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */; };
|
||||||
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; };
|
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; };
|
||||||
18B9763F2C11BA4A009271DF /* CarouselPaginationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */; };
|
18B9763F2C11BA4A009271DF /* CarouselPaginationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */; };
|
||||||
|
18C0F9462C98175900E1DD71 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C0F9452C98175900E1DD71 /* Modal.swift */; };
|
||||||
|
18C0F94A2C9817C100E1DD71 /* ModalChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18C0F9492C9817C100E1DD71 /* ModalChangeLog.txt */; };
|
||||||
18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; };
|
18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; };
|
||||||
18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */; };
|
18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */; };
|
||||||
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
|
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
|
||||||
@ -221,6 +227,10 @@
|
|||||||
180636C82C29B0DF00C92D86 /* InputStepperLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = InputStepperLog.txt; sourceTree = "<group>"; };
|
180636C82C29B0DF00C92D86 /* InputStepperLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = InputStepperLog.txt; sourceTree = "<group>"; };
|
||||||
1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselScrollbar.swift; sourceTree = "<group>"; };
|
1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselScrollbar.swift; sourceTree = "<group>"; };
|
||||||
1808BEBF2BA456B700129230 /* CarouselScrollbarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CarouselScrollbarChangeLog.txt; sourceTree = "<group>"; };
|
1808BEBF2BA456B700129230 /* CarouselScrollbarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CarouselScrollbarChangeLog.txt; sourceTree = "<group>"; };
|
||||||
|
1818D04C2C9BD2170053E73C /* ModalDialogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalDialogViewController.swift; sourceTree = "<group>"; };
|
||||||
|
1818D04E2C9BD3F60053E73C /* ModalDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalDialog.swift; sourceTree = "<group>"; };
|
||||||
|
1818D0502C9BD4090053E73C /* ModalLaunchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalLaunchable.swift; sourceTree = "<group>"; };
|
||||||
|
1818D0522C9BD47C0053E73C /* ModalModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalModel.swift; sourceTree = "<group>"; };
|
||||||
1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = "<group>"; };
|
1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = "<group>"; };
|
||||||
183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselSlotCell.swift; sourceTree = "<group>"; };
|
183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselSlotCell.swift; sourceTree = "<group>"; };
|
||||||
183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FootnoteGroup.swift; sourceTree = "<group>"; };
|
183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FootnoteGroup.swift; sourceTree = "<group>"; };
|
||||||
@ -246,6 +256,8 @@
|
|||||||
18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = "<group>"; };
|
18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = "<group>"; };
|
||||||
18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselPaginationModel.swift; sourceTree = "<group>"; };
|
18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselPaginationModel.swift; sourceTree = "<group>"; };
|
||||||
18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = "<group>"; };
|
18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = "<group>"; };
|
||||||
|
18C0F9452C98175900E1DD71 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = "<group>"; };
|
||||||
|
18C0F9492C9817C100E1DD71 /* ModalChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ModalChangeLog.txt; sourceTree = "<group>"; };
|
||||||
18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarIndicatorModel.swift; sourceTree = "<group>"; };
|
18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarIndicatorModel.swift; sourceTree = "<group>"; };
|
||||||
18FEA1B42BE0E63600A56439 /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = "<group>"; };
|
18FEA1B42BE0E63600A56439 /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = "<group>"; };
|
||||||
18FEA1B82BE1301700A56439 /* CalendarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CalendarChangeLog.txt; sourceTree = "<group>"; };
|
18FEA1B82BE1301700A56439 /* CalendarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CalendarChangeLog.txt; sourceTree = "<group>"; };
|
||||||
@ -554,6 +566,19 @@
|
|||||||
path = Carousel;
|
path = Carousel;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
18C0F9442C980CE500E1DD71 /* Modal */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
18C0F9452C98175900E1DD71 /* Modal.swift */,
|
||||||
|
1818D04E2C9BD3F60053E73C /* ModalDialog.swift */,
|
||||||
|
1818D04C2C9BD2170053E73C /* ModalDialogViewController.swift */,
|
||||||
|
1818D0502C9BD4090053E73C /* ModalLaunchable.swift */,
|
||||||
|
1818D0522C9BD47C0053E73C /* ModalModel.swift */,
|
||||||
|
18C0F9492C9817C100E1DD71 /* ModalChangeLog.txt */,
|
||||||
|
);
|
||||||
|
path = Modal;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
440B84C82BD8E0CE004A732A /* Table */ = {
|
440B84C82BD8E0CE004A732A /* Table */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -735,6 +760,7 @@
|
|||||||
EA3362412892EF700071C351 /* Label */,
|
EA3362412892EF700071C351 /* Label */,
|
||||||
44604AD529CE195300E62B51 /* Line */,
|
44604AD529CE195300E62B51 /* Line */,
|
||||||
EAD0688C2A55F801002E3A2D /* Loader */,
|
EAD0688C2A55F801002E3A2D /* Loader */,
|
||||||
|
18C0F9442C980CE500E1DD71 /* Modal */,
|
||||||
445BA07629C07ABA0036A7C5 /* Notification */,
|
445BA07629C07ABA0036A7C5 /* Notification */,
|
||||||
71B23C2B2B91FA510027F7D9 /* Pagination */,
|
71B23C2B2B91FA510027F7D9 /* Pagination */,
|
||||||
184023432C61E78D00A412C8 /* PriceLockup */,
|
184023432C61E78D00A412C8 /* PriceLockup */,
|
||||||
@ -1245,6 +1271,7 @@
|
|||||||
EA3362062891E14D0071C351 /* VerizonNHGeTX-Regular.otf in Resources */,
|
EA3362062891E14D0071C351 /* VerizonNHGeTX-Regular.otf in Resources */,
|
||||||
EA3362052891E14D0071C351 /* VerizonNHGeDS-Bold.otf in Resources */,
|
EA3362052891E14D0071C351 /* VerizonNHGeDS-Bold.otf in Resources */,
|
||||||
180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */,
|
180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */,
|
||||||
|
18C0F94A2C9817C100E1DD71 /* ModalChangeLog.txt in Resources */,
|
||||||
EAA5EEB928ECD24B003B3210 /* Icons.xcassets in Resources */,
|
EAA5EEB928ECD24B003B3210 /* Icons.xcassets in Resources */,
|
||||||
EAA5EEE428F5B855003B3210 /* VerizonNHGDS-Light.otf in Resources */,
|
EAA5EEE428F5B855003B3210 /* VerizonNHGDS-Light.otf in Resources */,
|
||||||
);
|
);
|
||||||
@ -1330,6 +1357,7 @@
|
|||||||
EA8141102A127066004F60D2 /* UIColor+VDSColor.swift in Sources */,
|
EA8141102A127066004F60D2 /* UIColor+VDSColor.swift in Sources */,
|
||||||
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
|
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
|
||||||
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */,
|
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */,
|
||||||
|
18C0F9462C98175900E1DD71 /* Modal.swift in Sources */,
|
||||||
EAC925842911C63100091998 /* Colorable.swift in Sources */,
|
EAC925842911C63100091998 /* Colorable.swift in Sources */,
|
||||||
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */,
|
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */,
|
||||||
EAF2F4762C231EAA007BFEDC /* AccessibilityActionElement.swift in Sources */,
|
EAF2F4762C231EAA007BFEDC /* AccessibilityActionElement.swift in Sources */,
|
||||||
@ -1347,6 +1375,7 @@
|
|||||||
EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */,
|
EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */,
|
||||||
71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */,
|
71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */,
|
||||||
EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */,
|
EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */,
|
||||||
|
1818D0512C9BD4090053E73C /* ModalLaunchable.swift in Sources */,
|
||||||
EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */,
|
EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */,
|
||||||
EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */,
|
EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */,
|
||||||
EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */,
|
EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */,
|
||||||
@ -1399,6 +1428,7 @@
|
|||||||
EAF2F4892C2A1075007BFEDC /* AlertViewController.swift in Sources */,
|
EAF2F4892C2A1075007BFEDC /* AlertViewController.swift in Sources */,
|
||||||
EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */,
|
EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */,
|
||||||
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */,
|
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */,
|
||||||
|
1818D04F2C9BD3F60053E73C /* ModalDialog.swift in Sources */,
|
||||||
EAC58C0C2BED01D500BA39FA /* Telephone.swift in Sources */,
|
EAC58C0C2BED01D500BA39FA /* Telephone.swift in Sources */,
|
||||||
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
|
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
|
||||||
EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */,
|
EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */,
|
||||||
@ -1451,6 +1481,7 @@
|
|||||||
EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */,
|
EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */,
|
||||||
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
|
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
|
||||||
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,
|
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,
|
||||||
|
1818D04D2C9BD2170053E73C /* ModalDialogViewController.swift in Sources */,
|
||||||
EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */,
|
EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */,
|
||||||
71FC86E02B973AE500700965 /* DropShadowConfiguration.swift in Sources */,
|
71FC86E02B973AE500700965 /* DropShadowConfiguration.swift in Sources */,
|
||||||
EA3362302891EB4A0071C351 /* Font.swift in Sources */,
|
EA3362302891EB4A0071C351 /* Font.swift in Sources */,
|
||||||
@ -1459,6 +1490,7 @@
|
|||||||
EAB5FEF12927F4AA00998C17 /* SelfSizingCollectionView.swift in Sources */,
|
EAB5FEF12927F4AA00998C17 /* SelfSizingCollectionView.swift in Sources */,
|
||||||
184023452C61E7AD00A412C8 /* PriceLockup.swift in Sources */,
|
184023452C61E7AD00A412C8 /* PriceLockup.swift in Sources */,
|
||||||
EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */,
|
EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */,
|
||||||
|
1818D0532C9BD47C0053E73C /* ModalModel.swift in Sources */,
|
||||||
EA3361A8288B23300071C351 /* UIColor.swift in Sources */,
|
EA3361A8288B23300071C351 /* UIColor.swift in Sources */,
|
||||||
EA2DC9B42BE2C6FE004F58C5 /* TextField.swift in Sources */,
|
EA2DC9B42BE2C6FE004F58C5 /* TextField.swift in Sources */,
|
||||||
EAC58C182BED0E2300BA39FA /* SecurityCode.swift in Sources */,
|
EAC58C182BED0E2300BA39FA /* SecurityCode.swift in Sources */,
|
||||||
|
|||||||
150
VDS/Components/Modal/Modal.swift
Normal file
150
VDS/Components/Modal/Modal.swift
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
//
|
||||||
|
// Modal.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Kanamarlapudi, Vasavi on 05/09/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import VDSCoreTokens
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
/// A Modal is an overlay that interrupts the user flow to force the customer to provide information or a response.
|
||||||
|
/// After the customer interacts with the modal, they can return to the parent content.
|
||||||
|
@objcMembers
|
||||||
|
@objc(VDSModal)
|
||||||
|
open class Modal: Control, ModalLaunchable {
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
required public init() {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override init(frame: CGRect) {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Private Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
internal var showModalButton = Button().with {
|
||||||
|
$0.use = .primary
|
||||||
|
$0.text = "Show Modal"
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Public Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
/// Text rendered for the title of the modal
|
||||||
|
open var title: String? { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// Text rendered for the content of the modal
|
||||||
|
open var content: String? { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// UIView rendered for the content area of the modal
|
||||||
|
open var contentView: UIView? { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// Array of Buttonable Views that are shown as Modal Footer. Primary and Close button data for modal button group.
|
||||||
|
open var buttonData: [ButtonBase]? { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// If provided, the Modal has the option to be displayed at full screen.
|
||||||
|
open var fullScreenDialog: Bool = false { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// If provided, close button can not be present.
|
||||||
|
open var hideCloseButton: Bool = false { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
addSubview(showModalButton)
|
||||||
|
showModalButton.pinToSuperView()
|
||||||
|
backgroundColor = .clear
|
||||||
|
|
||||||
|
isAccessibilityElement = true
|
||||||
|
accessibilityTraits = .button
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setDefaults() {
|
||||||
|
super.setDefaults()
|
||||||
|
title = nil
|
||||||
|
content = nil
|
||||||
|
contentView = nil
|
||||||
|
buttonData = nil
|
||||||
|
fullScreenDialog = false
|
||||||
|
hideCloseButton = false
|
||||||
|
|
||||||
|
showModalButton.onClick = { _ in self.showModalButtonClick() }
|
||||||
|
|
||||||
|
bridge_accessibilityLabelBlock = { [weak self] in
|
||||||
|
guard let self else { return "" }
|
||||||
|
var label = title
|
||||||
|
if label == nil {
|
||||||
|
label = content
|
||||||
|
}
|
||||||
|
if let label, !label.isEmpty {
|
||||||
|
return label
|
||||||
|
} else {
|
||||||
|
return "Modal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge_accessibilityHintBlock = { [weak self] in
|
||||||
|
guard let self else { return "" }
|
||||||
|
return isEnabled ? "Double tap to open." : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func showModalButtonClick() {
|
||||||
|
self.presentModal(surface: self.surface,
|
||||||
|
modalModel: .init(closeButtonText: showModalButton.text ?? "",
|
||||||
|
title: title,
|
||||||
|
content: content,
|
||||||
|
contentView: contentView,
|
||||||
|
buttonData: buttonData,
|
||||||
|
fullScreenDialog: fullScreenDialog,
|
||||||
|
hideCloseButton: hideCloseButton),
|
||||||
|
presenter: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Used to make changes to the View based off a change events or from local properties.
|
||||||
|
open override func updateView() {
|
||||||
|
super.updateView()
|
||||||
|
showModalButton.surface = surface
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func accessibleText(for title: String?, content: String?, closeButtonText: String) -> String {
|
||||||
|
var label = ""
|
||||||
|
if let title {
|
||||||
|
label = title
|
||||||
|
}
|
||||||
|
if let content {
|
||||||
|
if !label.isEmpty {
|
||||||
|
label += ","
|
||||||
|
}
|
||||||
|
label += content
|
||||||
|
}
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: AppleGuidelinesTouchable
|
||||||
|
extension Modal: AppleGuidelinesTouchable {
|
||||||
|
/// Overrides to ensure that the touch point meets a minimum of the minimumTappableArea.
|
||||||
|
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||||
|
Self.acceptablyOutsideBounds(point: point, bounds: bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
67
VDS/Components/Modal/ModalChangeLog.txt
Normal file
67
VDS/Components/Modal/ModalChangeLog.txt
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
MM/DD/YYYY
|
||||||
|
----------------
|
||||||
|
- Initial Brand 3.0 handoff
|
||||||
|
|
||||||
|
12/17/2021
|
||||||
|
----------------
|
||||||
|
- Replaced focusring colors (previously interactive/onlight/ondark) with accessibility/onlight/ondark colors
|
||||||
|
- Updated focus border name (previously interactive.focusring.onlight) with focusring.onlight/ondark
|
||||||
|
|
||||||
|
12/31/2021
|
||||||
|
----------------
|
||||||
|
- Updated Hover and Active state trigger specs. If triggered by mouse, Active same as Hover. If not, Active same as Default.
|
||||||
|
|
||||||
|
03/01/2022
|
||||||
|
----------------
|
||||||
|
- Replaced Close Non-Scaling icon with VDS Icon.
|
||||||
|
- Removed “vector effect” from Anatomy.
|
||||||
|
- Removed “weight” from Configurations.
|
||||||
|
|
||||||
|
08/10/2022
|
||||||
|
----------------
|
||||||
|
- Updated default and inverted prop to light and dark surface.
|
||||||
|
- Noted that button is optional within anatomy
|
||||||
|
|
||||||
|
09/06/2022
|
||||||
|
----------------
|
||||||
|
- Updated Anatomy element names to remove the word “Modal” from text elements, updated Button to be Button Group,
|
||||||
|
and noted Button Group as optional across all visuals within Anatomy.
|
||||||
|
|
||||||
|
11/30/2022
|
||||||
|
----------------
|
||||||
|
- Added "(web only)" to any instance of "keyboard focus"
|
||||||
|
|
||||||
|
12/13/2022
|
||||||
|
----------------
|
||||||
|
- Replaced focus border pixel and style & spacing values with tokens.
|
||||||
|
|
||||||
|
04/24/2023
|
||||||
|
----------------
|
||||||
|
- Updated all instances of Close Button (VDS Icon) with VDS Button Icon (size small)
|
||||||
|
- Button Icon placed 8px from top/right edge
|
||||||
|
- Use the Ghost variant of Button Icon
|
||||||
|
- Added Button Icon props to Elements spec
|
||||||
|
|
||||||
|
10/17/2023
|
||||||
|
----------------
|
||||||
|
- Added component tokens table
|
||||||
|
- Applied component tokens to light, dark surface configurations
|
||||||
|
|
||||||
|
11/22/2023
|
||||||
|
----------------
|
||||||
|
- Updated tab/desk visuals to reflect new corner radius value - 12px
|
||||||
|
- Updated border radius value in Anatomy
|
||||||
|
|
||||||
|
11/27/2023
|
||||||
|
----------------
|
||||||
|
- Updated ‘border radius” to “corner radius” in Anatomy
|
||||||
|
|
||||||
|
12/1/2023
|
||||||
|
----------------
|
||||||
|
- Applied palette tokens instead of hardcoded values where component tokens included an opacity
|
||||||
|
- Removed layer opacity annotation for instances where opacity is built into a component token
|
||||||
|
|
||||||
|
07/18/2024
|
||||||
|
----------------
|
||||||
|
- Added Scrollbar hit area with z-index specifications to the Behaviors page
|
||||||
|
- Decreased the height of the Grab zone to equal the height of the scrollbar thumb on the Behaviors page
|
||||||
238
VDS/Components/Modal/ModalDialog.swift
Normal file
238
VDS/Components/Modal/ModalDialog.swift
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
//
|
||||||
|
// ModalDialog.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Kanamarlapudi, Vasavi on 09/09/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import VDSCoreTokens
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
|
@objc(VDSModalDialog)
|
||||||
|
open class ModalDialog: View, UIScrollViewDelegate, ParentViewProtocol {
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
required public init() {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override init(frame: CGRect) {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Public Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
open var children: [any ViewProtocol] { [closeCrossButton, titleLabel, contentLabel, buttonGroupData] }
|
||||||
|
|
||||||
|
open var modalModel = Modal.ModalModel() { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
open var titleLabel = Label().with { label in
|
||||||
|
label.isAccessibilityElement = true
|
||||||
|
label.textStyle = .boldTitleLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
open var contentLabel = Label().with { label in
|
||||||
|
label.isAccessibilityElement = true
|
||||||
|
label.textStyle = .bodyLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
open lazy var closeCrossButton = ButtonIcon().with {
|
||||||
|
$0.kind = .ghost
|
||||||
|
$0.surfaceType = .colorFill
|
||||||
|
$0.iconName = .close
|
||||||
|
$0.size = .small
|
||||||
|
$0.customContainerSize = UIDevice.isIPad ? 48 : 48
|
||||||
|
$0.customIconSize = UIDevice.isIPad ? 32 : 32
|
||||||
|
}
|
||||||
|
|
||||||
|
open var buttonGroupData = ButtonGroup().with {
|
||||||
|
$0.alignment = .left
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Private Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
private var scrollView = UIScrollView().with {
|
||||||
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
$0.backgroundColor = .clear
|
||||||
|
}
|
||||||
|
|
||||||
|
private var contentStackView = UIStackView().with {
|
||||||
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
$0.axis = .vertical
|
||||||
|
$0.alignment = .leading
|
||||||
|
$0.distribution = .fillProportionally
|
||||||
|
$0.spacing = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy var primaryAccessibilityElement = UIAccessibilityElement(accessibilityContainer: self).with {
|
||||||
|
$0.accessibilityLabel = "Modal"
|
||||||
|
}
|
||||||
|
|
||||||
|
// close button with the 48 x 48 px
|
||||||
|
private var closeCrossButtonSize = 48.0
|
||||||
|
|
||||||
|
private let containerViewInset = UIDevice.isIPad ? VDSLayout.space12X : VDSLayout.space4X
|
||||||
|
private let contentLabelTopSpace = UIDevice.isIPad ? VDSLayout.space8X : VDSLayout.space6X
|
||||||
|
private let contentLabelBottomSpace = UIDevice.isIPad ? VDSLayout.space8X : VDSLayout.space12X
|
||||||
|
private let gapBetweenButtonItems = VDSLayout.space3X
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Configuration Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark)
|
||||||
|
private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark)
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
private var contentStackViewBottomConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
titleLabel.accessibilityTraits = .header
|
||||||
|
layer.cornerRadius = 12
|
||||||
|
|
||||||
|
// Add titleLabel, contentLabel to contentStack.
|
||||||
|
contentStackView.addArrangedSubview(titleLabel)
|
||||||
|
contentStackView.addArrangedSubview(contentLabel)
|
||||||
|
contentStackView.setCustomSpacing(contentLabelTopSpace, after: titleLabel)
|
||||||
|
scrollView.addSubview(contentStackView)
|
||||||
|
|
||||||
|
// Add crossButon, scrollView, buttonsData.
|
||||||
|
addSubview(closeCrossButton)
|
||||||
|
addSubview(scrollView)
|
||||||
|
addSubview(buttonGroupData)
|
||||||
|
self.bringSubviewToFront(closeCrossButton)
|
||||||
|
|
||||||
|
let crossTopSpace = UIDevice.isIPad && !modalModel.fullScreenDialog ? 0 : VDSLayout.space12X
|
||||||
|
let scrollTopSpace = UIDevice.isIPad && !modalModel.fullScreenDialog ? containerViewInset : (crossTopSpace + closeCrossButtonSize)
|
||||||
|
let contentTrailingSpace = UIDevice.isIPad ? (containerViewInset/2) - 6 : containerViewInset
|
||||||
|
|
||||||
|
// Activate constraints
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
// Constraints for the closeCrossButton
|
||||||
|
closeCrossButton.topAnchor.constraint(equalTo: topAnchor, constant: crossTopSpace),
|
||||||
|
closeCrossButton.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor),
|
||||||
|
closeCrossButton.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||||
|
closeCrossButton.heightAnchor.constraint(equalToConstant: closeCrossButtonSize),
|
||||||
|
|
||||||
|
// Constraints for the bottom button view
|
||||||
|
buttonGroupData.leadingAnchor.constraint(equalTo: leadingAnchor, constant:containerViewInset),
|
||||||
|
buttonGroupData.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -containerViewInset),
|
||||||
|
buttonGroupData.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -containerViewInset),
|
||||||
|
|
||||||
|
// Constraints for the scrollView
|
||||||
|
scrollView.topAnchor.constraint(equalTo: topAnchor, constant: scrollTopSpace),
|
||||||
|
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor, constant:containerViewInset),
|
||||||
|
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -contentTrailingSpace),
|
||||||
|
scrollView.bottomAnchor.constraint(equalTo: buttonGroupData.topAnchor, constant: -contentLabelBottomSpace),
|
||||||
|
|
||||||
|
// Constraints for the contentStackView
|
||||||
|
contentStackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
|
||||||
|
contentStackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
|
||||||
|
contentStackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -contentTrailingSpace),
|
||||||
|
contentStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -contentTrailingSpace),
|
||||||
|
contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
contentStackViewBottomConstraint = contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
|
||||||
|
contentStackViewBottomConstraint?.activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to make changes to the View based off a change events or from local properties.
|
||||||
|
open override func updateView() {
|
||||||
|
super.updateView()
|
||||||
|
|
||||||
|
// Update surface and background
|
||||||
|
backgroundColor = backgroundColorConfiguration.getColor(self)
|
||||||
|
scrollView.indicatorStyle = surface == .light ? .black : .white
|
||||||
|
closeCrossButton.surface = surface
|
||||||
|
buttonGroupData.surface = surface
|
||||||
|
titleLabel.surface = surface
|
||||||
|
contentLabel.surface = surface
|
||||||
|
|
||||||
|
// Re-arrange contentStack
|
||||||
|
contentStackView.removeArrangedSubviews()
|
||||||
|
|
||||||
|
titleLabel.text = modalModel.title
|
||||||
|
contentLabel.text = modalModel.content
|
||||||
|
titleLabel.textColor = textColorConfiguration.getColor(self)
|
||||||
|
contentLabel.textColor = textColorConfiguration.getColor(self)
|
||||||
|
titleLabel.sizeToFit()
|
||||||
|
contentLabel.sizeToFit()
|
||||||
|
|
||||||
|
// Add buttons data if provided
|
||||||
|
if let buttons = modalModel.buttonData, buttons.count > 0 {
|
||||||
|
buttonGroupData.buttons = buttons
|
||||||
|
let percent = UIDevice.isIPad ? 50.0 : 100.0
|
||||||
|
buttonGroupData.rowQuantityTablet = 2
|
||||||
|
buttonGroupData.rowQuantityPhone = 1
|
||||||
|
buttonGroupData.childWidth = .percentage(percent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update title, content and contentview
|
||||||
|
var addedTitle = false
|
||||||
|
|
||||||
|
if let titleText = modalModel.title, !titleText.isEmpty {
|
||||||
|
contentStackView.addArrangedSubview(titleLabel)
|
||||||
|
addedTitle = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var addedContent = false
|
||||||
|
if let contentText = modalModel.content, !contentText.isEmpty {
|
||||||
|
contentStackView.addArrangedSubview(contentLabel)
|
||||||
|
addedContent = true
|
||||||
|
} else if let contentView = modalModel.contentView {
|
||||||
|
contentView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
if var surfaceable = contentView as? Surfaceable {
|
||||||
|
surfaceable.surface = surface
|
||||||
|
}
|
||||||
|
contentStackView.addArrangedSubview(contentView)
|
||||||
|
addedContent = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if addedTitle && addedContent {
|
||||||
|
contentStackView.spacing = contentLabelTopSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
closeCrossButton.isHidden = modalModel.hideCloseButton
|
||||||
|
|
||||||
|
contentStackView.setNeedsLayout()
|
||||||
|
contentStackView.layoutIfNeeded()
|
||||||
|
scrollView.setNeedsLayout()
|
||||||
|
scrollView.layoutIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to update any Accessibility properties.
|
||||||
|
open override func updateAccessibility() {
|
||||||
|
super.updateAccessibility()
|
||||||
|
primaryAccessibilityElement.accessibilityHint = "Double tap on the cross button to close."
|
||||||
|
primaryAccessibilityElement.accessibilityFrameInContainerSpace = .init(origin: .zero, size: frame.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override var accessibilityElements: [Any]? {
|
||||||
|
get {
|
||||||
|
var elements: [Any] = [primaryAccessibilityElement]
|
||||||
|
contentStackView.arrangedSubviews.forEach{ elements.append($0) }
|
||||||
|
elements.append(buttonGroupData)
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
set {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
124
VDS/Components/Modal/ModalDialogViewController.swift
Normal file
124
VDS/Components/Modal/ModalDialogViewController.swift
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
//
|
||||||
|
// ModalDialogViewController.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Kanamarlapudi, Vasavi on 09/09/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Combine
|
||||||
|
import VDSCoreTokens
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
|
@objc(VDSModalDialogViewController)
|
||||||
|
open class ModalDialogViewController: UIViewController, Surfaceable {
|
||||||
|
|
||||||
|
/// Set of Subscribers for any Publishers for this Control.
|
||||||
|
open var subscribers = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Private Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
private var onClickSubscriber: AnyCancellable? {
|
||||||
|
willSet {
|
||||||
|
if let onClickSubscriber {
|
||||||
|
onClickSubscriber.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let modalDialog = ModalDialog()
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Public Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
/// Current Surface and this is used to pass down to child objects that implement Surfacable
|
||||||
|
open var surface: Surface = .light { didSet { updateView() }}
|
||||||
|
open var modalModel = Modal.ModalModel() { didSet { updateView() }}
|
||||||
|
open var presenter: UIView? { didSet { updateView() }}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Configuration
|
||||||
|
//--------------------------------------------------
|
||||||
|
private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite)
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
open override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
isModalInPresentation = true
|
||||||
|
setup()
|
||||||
|
}
|
||||||
|
open override func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
UIAccessibility.post(notification: .screenChanged, argument: modalDialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dismiss() {
|
||||||
|
dismiss(animated: true) { [weak self] in
|
||||||
|
guard let self, let presenter else { return }
|
||||||
|
UIAccessibility.post(notification: .layoutChanged, argument: presenter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open func setup() {
|
||||||
|
view.accessibilityElements = [modalDialog]
|
||||||
|
|
||||||
|
//left-right swipe
|
||||||
|
view.publisher(for: UISwipeGestureRecognizer().with{ $0.direction = .right })
|
||||||
|
.sink { [weak self] swipe in
|
||||||
|
guard let self, !UIAccessibility.isVoiceOverRunning else { return }
|
||||||
|
self.dismiss()
|
||||||
|
}.store(in: &subscribers)
|
||||||
|
|
||||||
|
//tapping in background
|
||||||
|
view.publisher(for: UITapGestureRecognizer().with{ $0.numberOfTapsRequired = 1 })
|
||||||
|
.sink { [weak self] swipe in
|
||||||
|
guard let self, !UIAccessibility.isVoiceOverRunning else { return }
|
||||||
|
self.dismiss()
|
||||||
|
}.store(in: &subscribers)
|
||||||
|
|
||||||
|
//clicking button
|
||||||
|
onClickSubscriber = modalDialog.closeCrossButton.publisher(for: .touchUpInside)
|
||||||
|
.sink {[weak self] button in
|
||||||
|
guard let self else { return }
|
||||||
|
self.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
view.addSubview(modalDialog)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to make changes to the View based off a change events or from local properties.
|
||||||
|
open func updateView() {
|
||||||
|
modalDialog.surface = surface
|
||||||
|
modalDialog.modalModel = modalModel
|
||||||
|
|
||||||
|
|
||||||
|
// Activate constraints
|
||||||
|
modalDialog.removeConstraints()
|
||||||
|
let isFullScreen = UIDevice.isIPad && !modalModel.fullScreenDialog ? false : true
|
||||||
|
|
||||||
|
if isFullScreen {
|
||||||
|
view.backgroundColor = modalDialog.backgroundColor
|
||||||
|
modalDialog
|
||||||
|
.pinLeading()
|
||||||
|
.pinTrailing()
|
||||||
|
modalDialog.pinTop(anchor: UIDevice.isIPad ? view.safeAreaLayoutGuide.topAnchor : view.topAnchor)
|
||||||
|
modalDialog.pinBottom(UIDevice.isIPad ? view.bottomAnchor : view.safeAreaLayoutGuide.bottomAnchor)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
view.backgroundColor = backgroundColorConfiguration.getColor(self).withAlphaComponent(0.8)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
// Constraints for the floating modal view for Tablet.
|
||||||
|
modalDialog.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||||
|
modalDialog.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||||
|
modalDialog.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.7),
|
||||||
|
modalDialog.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.7)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
28
VDS/Components/Modal/ModalLaunchable.swift
Normal file
28
VDS/Components/Modal/ModalLaunchable.swift
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// ModalLaunchable.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Kanamarlapudi, Vasavi on 09/09/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
public protocol ModalLaunchable {
|
||||||
|
func presentModal(surface: Surface, modalModel: Modal.ModalModel, presenter: UIView?)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ModalLaunchable {
|
||||||
|
public func presentModal(surface: Surface, modalModel: Modal.ModalModel, presenter: UIView? = nil) {
|
||||||
|
if let presenting = UIApplication.topViewController() {
|
||||||
|
let modalViewController = ModalDialogViewController(nibName: nil, bundle: nil).with {
|
||||||
|
$0.surface = surface
|
||||||
|
$0.modalModel = modalModel
|
||||||
|
$0.presenter = presenter
|
||||||
|
$0.modalPresentationStyle = UIDevice.isIPad && !modalModel.fullScreenDialog ? .overCurrentContext : .fullScreen
|
||||||
|
$0.modalTransitionStyle = .crossDissolve
|
||||||
|
}
|
||||||
|
presenting.present(modalViewController, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
VDS/Components/Modal/ModalModel.swift
Normal file
45
VDS/Components/Modal/ModalModel.swift
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// ModalModel.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Kanamarlapudi, Vasavi on 09/09/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension Modal {
|
||||||
|
|
||||||
|
/// Model used to represent the modal.
|
||||||
|
public struct ModalModel: Equatable {
|
||||||
|
/// Current Surface and this is used to pass down to child objects that implement Surfacable
|
||||||
|
public var closeButtonText: String
|
||||||
|
public var title: String?
|
||||||
|
public var content: String?
|
||||||
|
public var contentView: UIView?
|
||||||
|
public var accessibleText: String?
|
||||||
|
public var contentViewAlignment: UIStackView.Alignment?
|
||||||
|
public var buttonData: [ButtonBase]?
|
||||||
|
public var fullScreenDialog: Bool
|
||||||
|
public var hideCloseButton: Bool
|
||||||
|
public init(closeButtonText: String = "Close",
|
||||||
|
title: String? = nil,
|
||||||
|
content: String? = nil,
|
||||||
|
contentView: UIView? = nil,
|
||||||
|
buttonData: [ButtonBase]? = nil,
|
||||||
|
fullScreenDialog: Bool = false,
|
||||||
|
hideCloseButton: Bool = false,
|
||||||
|
accessibleText: String? = "Modal",
|
||||||
|
contentViewAlignment: UIStackView.Alignment = .leading) {
|
||||||
|
self.closeButtonText = closeButtonText
|
||||||
|
self.title = title
|
||||||
|
self.content = content
|
||||||
|
self.contentView = contentView
|
||||||
|
self.accessibleText = accessibleText
|
||||||
|
self.contentViewAlignment = contentViewAlignment
|
||||||
|
self.buttonData = buttonData
|
||||||
|
self.fullScreenDialog = fullScreenDialog
|
||||||
|
self.hideCloseButton = hideCloseButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -40,6 +40,7 @@ Using the system allows designers and developers to collaborate more easily and
|
|||||||
- ``Label``
|
- ``Label``
|
||||||
- ``Line``
|
- ``Line``
|
||||||
- ``Loader``
|
- ``Loader``
|
||||||
|
- ``Modal``
|
||||||
- ``Notification``
|
- ``Notification``
|
||||||
- ``Pagination``
|
- ``Pagination``
|
||||||
- ``PriceLockup``
|
- ``PriceLockup``
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user