Compare commits
No commits in common. "develop" and "release/20_2_0" have entirely different histories.
develop
...
release/20
@ -10,25 +10,15 @@
|
|||||||
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 */; };
|
|
||||||
183B16F72C80B32200BA6A10 /* FootnoteGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */; };
|
|
||||||
184023452C61E7AD00A412C8 /* PriceLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184023442C61E7AD00A412C8 /* PriceLockup.swift */; };
|
184023452C61E7AD00A412C8 /* PriceLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184023442C61E7AD00A412C8 /* PriceLockup.swift */; };
|
||||||
184023472C61E7EC00A412C8 /* PriceLockupChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 184023462C61E7EC00A412C8 /* PriceLockupChangeLog.txt */; };
|
184023472C61E7EC00A412C8 /* PriceLockupChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 184023462C61E7EC00A412C8 /* PriceLockupChangeLog.txt */; };
|
||||||
1842B1DF2BECE28B0021AFCA /* CalendarDateViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */; };
|
1842B1DF2BECE28B0021AFCA /* CalendarDateViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */; };
|
||||||
1842B1E12BECE7B70021AFCA /* CalendarHeaderReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1E02BECE7B70021AFCA /* CalendarHeaderReusableView.swift */; };
|
1842B1E12BECE7B70021AFCA /* CalendarHeaderReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1E02BECE7B70021AFCA /* CalendarHeaderReusableView.swift */; };
|
||||||
1842B1E32BECF0A20021AFCA /* CalendarFooterReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1E22BECF0A10021AFCA /* CalendarFooterReusableView.swift */; };
|
1842B1E32BECF0A20021AFCA /* CalendarFooterReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1E22BECF0A10021AFCA /* CalendarFooterReusableView.swift */; };
|
||||||
1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */; };
|
1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */; };
|
||||||
1859B30F2CBF6FEB0031CD70 /* ListUnordered.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1859B30E2CBF6FDD0031CD70 /* ListUnordered.swift */; };
|
|
||||||
1859B31B2CBFA0180031CD70 /* ListUnorderedItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1859B31A2CBFA0180031CD70 /* ListUnorderedItemModel.swift */; };
|
|
||||||
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */; };
|
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */; };
|
||||||
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; };
|
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; };
|
||||||
18926F5B2C7616A500C55BF6 /* FootnoteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18926F5A2C7616A500C55BF6 /* FootnoteItem.swift */; };
|
|
||||||
18926F5D2C7616C600C55BF6 /* FootnoteChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */; };
|
|
||||||
18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1292BD9298900498E4A /* Calendar.swift */; };
|
18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1292BD9298900498E4A /* Calendar.swift */; };
|
||||||
18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; };
|
18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; };
|
||||||
18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; };
|
18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; };
|
||||||
@ -36,8 +26,6 @@
|
|||||||
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 */; };
|
||||||
@ -71,8 +59,6 @@
|
|||||||
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C402A6AD61C00E5C127 /* Typography+Additional.swift */; };
|
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C402A6AD61C00E5C127 /* Typography+Additional.swift */; };
|
||||||
EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C442A6AD73000E5C127 /* RawRepresentable.swift */; };
|
EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C442A6AD73000E5C127 /* RawRepresentable.swift */; };
|
||||||
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; };
|
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; };
|
||||||
EA225FC72CA4845100B6B3B3 /* LanguageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA225FC62CA4845100B6B3B3 /* LanguageManager.swift */; };
|
|
||||||
EA225FC92CA4932900B6B3B3 /* Typography+StyleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA225FC82CA4932900B6B3B3 /* Typography+StyleProvider.swift */; };
|
|
||||||
EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */; };
|
EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */; };
|
||||||
EA297A5729FB0A360031ED56 /* AppleGuidelinesTouchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */; };
|
EA297A5729FB0A360031ED56 /* AppleGuidelinesTouchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */; };
|
||||||
EA2DC9B02BE175BA004F58C5 /* RequiredRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */; };
|
EA2DC9B02BE175BA004F58C5 /* RequiredRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */; };
|
||||||
@ -229,13 +215,7 @@
|
|||||||
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>"; };
|
|
||||||
183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FootnoteGroup.swift; sourceTree = "<group>"; };
|
|
||||||
184023442C61E7AD00A412C8 /* PriceLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceLockup.swift; sourceTree = "<group>"; };
|
184023442C61E7AD00A412C8 /* PriceLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceLockup.swift; sourceTree = "<group>"; };
|
||||||
184023462C61E7EC00A412C8 /* PriceLockupChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PriceLockupChangeLog.txt; sourceTree = "<group>"; };
|
184023462C61E7EC00A412C8 /* PriceLockupChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PriceLockupChangeLog.txt; sourceTree = "<group>"; };
|
||||||
1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarDateViewCell.swift; sourceTree = "<group>"; };
|
1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarDateViewCell.swift; sourceTree = "<group>"; };
|
||||||
@ -243,15 +223,10 @@
|
|||||||
1842B1E22BECF0A10021AFCA /* CalendarFooterReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarFooterReusableView.swift; sourceTree = "<group>"; };
|
1842B1E22BECF0A10021AFCA /* CalendarFooterReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarFooterReusableView.swift; sourceTree = "<group>"; };
|
||||||
18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BreadcrumbsChangeLog.txt; sourceTree = "<group>"; };
|
18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BreadcrumbsChangeLog.txt; sourceTree = "<group>"; };
|
||||||
1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItemModel.swift; sourceTree = "<group>"; };
|
1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItemModel.swift; sourceTree = "<group>"; };
|
||||||
1859B30E2CBF6FDD0031CD70 /* ListUnordered.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListUnordered.swift; sourceTree = "<group>"; };
|
|
||||||
1859B3122CBF70AB0031CD70 /* ListUnordered.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ListUnordered.txt; sourceTree = "<group>"; };
|
|
||||||
1859B31A2CBFA0180031CD70 /* ListUnorderedItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListUnorderedItemModel.swift; sourceTree = "<group>"; };
|
|
||||||
186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextAreaChangeLog.txt; sourceTree = "<group>"; };
|
186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextAreaChangeLog.txt; sourceTree = "<group>"; };
|
||||||
186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownSelect.swift; sourceTree = "<group>"; };
|
186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownSelect.swift; sourceTree = "<group>"; };
|
||||||
186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = DropdownSelectChangeLog.txt; sourceTree = "<group>"; };
|
186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = DropdownSelectChangeLog.txt; sourceTree = "<group>"; };
|
||||||
18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = "<group>"; };
|
18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = "<group>"; };
|
||||||
18926F5A2C7616A500C55BF6 /* FootnoteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FootnoteItem.swift; sourceTree = "<group>"; };
|
|
||||||
18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = FootnoteChangeLog.txt; sourceTree = "<group>"; };
|
|
||||||
18A3F1292BD9298900498E4A /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = "<group>"; };
|
18A3F1292BD9298900498E4A /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = "<group>"; };
|
||||||
18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = "<group>"; };
|
18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = "<group>"; };
|
||||||
18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = "<group>"; };
|
18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = "<group>"; };
|
||||||
@ -261,8 +236,6 @@
|
|||||||
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>"; };
|
||||||
@ -277,7 +250,7 @@
|
|||||||
44CCF4942C0493A1005C9C5E /* TableChangeLog.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TableChangeLog.txt; sourceTree = "<group>"; };
|
44CCF4942C0493A1005C9C5E /* TableChangeLog.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TableChangeLog.txt; sourceTree = "<group>"; };
|
||||||
5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = "<group>"; };
|
5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = "<group>"; };
|
||||||
5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = "<group>"; };
|
5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = "<group>"; };
|
||||||
710607942B91A99500F2863F /* TileletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileletChangeLog.txt; sourceTree = "<group>"; };
|
710607942B91A99500F2863F /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = "<group>"; };
|
||||||
7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = "<group>"; };
|
7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = "<group>"; };
|
||||||
71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationContainer.swift; sourceTree = "<group>"; };
|
71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationContainer.swift; sourceTree = "<group>"; };
|
||||||
71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TiletEyebrowModel.swift; sourceTree = "<group>"; };
|
71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TiletEyebrowModel.swift; sourceTree = "<group>"; };
|
||||||
@ -305,8 +278,6 @@
|
|||||||
EA0D1C442A6AD73000E5C127 /* RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawRepresentable.swift; sourceTree = "<group>"; };
|
EA0D1C442A6AD73000E5C127 /* RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawRepresentable.swift; sourceTree = "<group>"; };
|
||||||
EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = "<group>"; };
|
EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = "<group>"; };
|
||||||
EA21C5DA2B600EDD00CFC139 /* VDSTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTokens.xcframework; path = ../SharedFrameworks/VDSTokens.xcframework; sourceTree = "<group>"; };
|
EA21C5DA2B600EDD00CFC139 /* VDSTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTokens.xcframework; path = ../SharedFrameworks/VDSTokens.xcframework; sourceTree = "<group>"; };
|
||||||
EA225FC62CA4845100B6B3B3 /* LanguageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageManager.swift; sourceTree = "<group>"; };
|
|
||||||
EA225FC82CA4932900B6B3B3 /* Typography+StyleProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Typography+StyleProvider.swift"; sourceTree = "<group>"; };
|
|
||||||
EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLabelAttribute.swift; sourceTree = "<group>"; };
|
EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLabelAttribute.swift; sourceTree = "<group>"; };
|
||||||
EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesTouchable.swift; sourceTree = "<group>"; };
|
EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesTouchable.swift; sourceTree = "<group>"; };
|
||||||
EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequiredRule.swift; sourceTree = "<group>"; };
|
EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequiredRule.swift; sourceTree = "<group>"; };
|
||||||
@ -513,16 +484,6 @@
|
|||||||
path = PriceLockup;
|
path = PriceLockup;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
1859B30D2CBF6EF80031CD70 /* ListUnordered */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
1859B30E2CBF6FDD0031CD70 /* ListUnordered.swift */,
|
|
||||||
1859B31A2CBFA0180031CD70 /* ListUnorderedItemModel.swift */,
|
|
||||||
1859B3122CBF70AB0031CD70 /* ListUnordered.txt */,
|
|
||||||
);
|
|
||||||
path = ListUnordered;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
186D13C92BBA8A3500986B53 /* DropdownSelect */ = {
|
186D13C92BBA8A3500986B53 /* DropdownSelect */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -533,16 +494,6 @@
|
|||||||
path = DropdownSelect;
|
path = DropdownSelect;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
18926F592C76168300C55BF6 /* Footnote */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
18926F5A2C7616A500C55BF6 /* FootnoteItem.swift */,
|
|
||||||
183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */,
|
|
||||||
18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */,
|
|
||||||
);
|
|
||||||
path = Footnote;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
18A3F1202BD8F5DE00498E4A /* Calendar */ = {
|
18A3F1202BD8F5DE00498E4A /* Calendar */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -573,7 +524,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
18AE874F2C06FDA60075F181 /* Carousel.swift */,
|
18AE874F2C06FDA60075F181 /* Carousel.swift */,
|
||||||
183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */,
|
|
||||||
18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */,
|
18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */,
|
||||||
18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */,
|
18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */,
|
||||||
18AE87532C06FE610075F181 /* CarouselChangeLog.txt */,
|
18AE87532C06FE610075F181 /* CarouselChangeLog.txt */,
|
||||||
@ -581,19 +531,6 @@
|
|||||||
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 = (
|
||||||
@ -769,14 +706,11 @@
|
|||||||
EAF7F092289985E200B287F5 /* Checkbox */,
|
EAF7F092289985E200B287F5 /* Checkbox */,
|
||||||
EAC58C1F2BF127F000BA39FA /* DatePicker */,
|
EAC58C1F2BF127F000BA39FA /* DatePicker */,
|
||||||
186D13C92BBA8A3500986B53 /* DropdownSelect */,
|
186D13C92BBA8A3500986B53 /* DropdownSelect */,
|
||||||
18926F592C76168300C55BF6 /* Footnote */,
|
|
||||||
EA985BF3296C609E00F2FF2E /* Icon */,
|
EA985BF3296C609E00F2FF2E /* Icon */,
|
||||||
180636C52C29B06200C92D86 /* InputStepper */,
|
180636C52C29B06200C92D86 /* InputStepper */,
|
||||||
EA3362412892EF700071C351 /* Label */,
|
EA3362412892EF700071C351 /* Label */,
|
||||||
44604AD529CE195300E62B51 /* Line */,
|
44604AD529CE195300E62B51 /* Line */,
|
||||||
1859B30D2CBF6EF80031CD70 /* ListUnordered */,
|
|
||||||
EAD0688C2A55F801002E3A2D /* Loader */,
|
EAD0688C2A55F801002E3A2D /* Loader */,
|
||||||
18C0F9442C980CE500E1DD71 /* Modal */,
|
|
||||||
445BA07629C07ABA0036A7C5 /* Notification */,
|
445BA07629C07ABA0036A7C5 /* Notification */,
|
||||||
71B23C2B2B91FA510027F7D9 /* Pagination */,
|
71B23C2B2B91FA510027F7D9 /* Pagination */,
|
||||||
184023432C61E78D00A412C8 /* PriceLockup */,
|
184023432C61E78D00A412C8 /* PriceLockup */,
|
||||||
@ -860,13 +794,12 @@
|
|||||||
EA3361B4288B2A360071C351 /* Classes */ = {
|
EA3361B4288B2A360071C351 /* Classes */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
EAF2F4752C231EAA007BFEDC /* AccessibilityActionElement.swift */,
|
|
||||||
EAF2F4882C2A1075007BFEDC /* AlertViewController.swift */,
|
|
||||||
EA985C1C296CD13600F2FF2E /* BundleManager.swift */,
|
EA985C1C296CD13600F2FF2E /* BundleManager.swift */,
|
||||||
EAC58C282BF4118C00BA39FA /* ClearPopoverViewController.swift */,
|
EAC58C282BF4118C00BA39FA /* ClearPopoverViewController.swift */,
|
||||||
EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */,
|
EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */,
|
||||||
EA225FC62CA4845100B6B3B3 /* LanguageManager.swift */,
|
|
||||||
EAB5FEF02927F4AA00998C17 /* SelfSizingCollectionView.swift */,
|
EAB5FEF02927F4AA00998C17 /* SelfSizingCollectionView.swift */,
|
||||||
|
EAF2F4752C231EAA007BFEDC /* AccessibilityActionElement.swift */,
|
||||||
|
EAF2F4882C2A1075007BFEDC /* AlertViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Classes;
|
path = Classes;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -979,7 +912,7 @@
|
|||||||
EA985BE72968951C00F2FF2E /* TileletTitleModel.swift */,
|
EA985BE72968951C00F2FF2E /* TileletTitleModel.swift */,
|
||||||
EA985BE929689B6D00F2FF2E /* TileletSubTitleModel.swift */,
|
EA985BE929689B6D00F2FF2E /* TileletSubTitleModel.swift */,
|
||||||
EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */,
|
EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */,
|
||||||
710607942B91A99500F2863F /* TileletChangeLog.txt */,
|
710607942B91A99500F2863F /* TitleletChangeLog.txt */,
|
||||||
);
|
);
|
||||||
path = Tilelet;
|
path = Tilelet;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1034,7 +967,6 @@
|
|||||||
EA0D1C3C2A6AD57600E5C127 /* Typography+Enums.swift */,
|
EA0D1C3C2A6AD57600E5C127 /* Typography+Enums.swift */,
|
||||||
EA0D1C382A6AD4DF00E5C127 /* Typography+SpacingConfig.swift */,
|
EA0D1C382A6AD4DF00E5C127 /* Typography+SpacingConfig.swift */,
|
||||||
EA0D1C3A2A6AD51B00E5C127 /* Typogprahy+Styles.swift */,
|
EA0D1C3A2A6AD51B00E5C127 /* Typogprahy+Styles.swift */,
|
||||||
EA225FC82CA4932900B6B3B3 /* Typography+StyleProvider.swift */,
|
|
||||||
);
|
);
|
||||||
path = Typography;
|
path = Typography;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1280,14 +1212,12 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
18926F5D2C7616C600C55BF6 /* FootnoteChangeLog.txt in Resources */,
|
|
||||||
EA3362042891E14D0071C351 /* VerizonNHGeTX-Bold.otf in Resources */,
|
EA3362042891E14D0071C351 /* VerizonNHGeTX-Bold.otf in Resources */,
|
||||||
184023472C61E7EC00A412C8 /* PriceLockupChangeLog.txt in Resources */,
|
184023472C61E7EC00A412C8 /* PriceLockupChangeLog.txt in Resources */,
|
||||||
EA3362072891E14D0071C351 /* VerizonNHGeDS-Regular.otf in Resources */,
|
EA3362072891E14D0071C351 /* VerizonNHGeDS-Regular.otf in Resources */,
|
||||||
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 */,
|
||||||
);
|
);
|
||||||
@ -1346,7 +1276,6 @@
|
|||||||
EA3361C328902D960071C351 /* Toggle.swift in Sources */,
|
EA3361C328902D960071C351 /* Toggle.swift in Sources */,
|
||||||
EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */,
|
EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */,
|
||||||
EAC58C232BF2824200BA39FA /* DatePicker.swift in Sources */,
|
EAC58C232BF2824200BA39FA /* DatePicker.swift in Sources */,
|
||||||
183B16F72C80B32200BA6A10 /* FootnoteGroup.swift in Sources */,
|
|
||||||
EA89201328B568D8006B9984 /* RadioBoxItem.swift in Sources */,
|
EA89201328B568D8006B9984 /* RadioBoxItem.swift in Sources */,
|
||||||
71FC86E42B9841AC00700965 /* PaginationFlowLayout.swift in Sources */,
|
71FC86E42B9841AC00700965 /* PaginationFlowLayout.swift in Sources */,
|
||||||
EAC9258C2911C9DE00091998 /* InputField.swift in Sources */,
|
EAC9258C2911C9DE00091998 /* InputField.swift in Sources */,
|
||||||
@ -1363,7 +1292,6 @@
|
|||||||
EA6642952BCEBF9500D81DC4 /* TextLinkModel.swift in Sources */,
|
EA6642952BCEBF9500D81DC4 /* TextLinkModel.swift in Sources */,
|
||||||
71FC86E22B97483000700965 /* Clamping.swift in Sources */,
|
71FC86E22B97483000700965 /* Clamping.swift in Sources */,
|
||||||
EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */,
|
EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */,
|
||||||
1859B30F2CBF6FEB0031CD70 /* ListUnordered.swift in Sources */,
|
|
||||||
1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */,
|
1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */,
|
||||||
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */,
|
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */,
|
||||||
EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */,
|
EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */,
|
||||||
@ -1374,12 +1302,10 @@
|
|||||||
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 */,
|
||||||
EAC58BFD2BE935C300BA39FA /* TitleLockupTextColor.swift in Sources */,
|
EAC58BFD2BE935C300BA39FA /* TitleLockupTextColor.swift in Sources */,
|
||||||
18926F5B2C7616A500C55BF6 /* FootnoteItem.swift in Sources */,
|
|
||||||
EAACB89A2B927108006A3869 /* Valuing.swift in Sources */,
|
EAACB89A2B927108006A3869 /* Valuing.swift in Sources */,
|
||||||
EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */,
|
EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */,
|
||||||
EAF193422C134F3400C68D18 /* Table.swift in Sources */,
|
EAF193422C134F3400C68D18 /* Table.swift in Sources */,
|
||||||
@ -1392,7 +1318,6 @@
|
|||||||
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 */,
|
||||||
@ -1422,7 +1347,6 @@
|
|||||||
44BD43B62C04866600644F87 /* TableRowModel.swift in Sources */,
|
44BD43B62C04866600644F87 /* TableRowModel.swift in Sources */,
|
||||||
71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */,
|
71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */,
|
||||||
EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */,
|
EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */,
|
||||||
EA225FC72CA4845100B6B3B3 /* LanguageManager.swift in Sources */,
|
|
||||||
EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */,
|
EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */,
|
||||||
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */,
|
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */,
|
||||||
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */,
|
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */,
|
||||||
@ -1431,7 +1355,6 @@
|
|||||||
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */,
|
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */,
|
||||||
18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */,
|
18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */,
|
||||||
71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */,
|
71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */,
|
||||||
1859B31B2CBFA0180031CD70 /* ListUnorderedItemModel.swift in Sources */,
|
|
||||||
EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */,
|
EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */,
|
||||||
EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */,
|
EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */,
|
||||||
EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */,
|
EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */,
|
||||||
@ -1446,7 +1369,6 @@
|
|||||||
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 */,
|
||||||
@ -1461,7 +1383,6 @@
|
|||||||
44604AD729CE196600E62B51 /* Line.swift in Sources */,
|
44604AD729CE196600E62B51 /* Line.swift in Sources */,
|
||||||
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */,
|
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */,
|
||||||
EAF978212A99035B00C2FEA9 /* Enabling.swift in Sources */,
|
EAF978212A99035B00C2FEA9 /* Enabling.swift in Sources */,
|
||||||
EA225FC92CA4932900B6B3B3 /* Typography+StyleProvider.swift in Sources */,
|
|
||||||
EAC58C062BED000200BA39FA /* CreditCard.swift in Sources */,
|
EAC58C062BED000200BA39FA /* CreditCard.swift in Sources */,
|
||||||
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */,
|
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */,
|
||||||
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */,
|
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */,
|
||||||
@ -1479,7 +1400,6 @@
|
|||||||
EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */,
|
EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */,
|
||||||
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
|
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
|
||||||
EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */,
|
EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */,
|
||||||
183B16F32C78CF7C00BA6A10 /* CarouselSlotCell.swift in Sources */,
|
|
||||||
44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */,
|
44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */,
|
||||||
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
|
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
|
||||||
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */,
|
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */,
|
||||||
@ -1499,7 +1419,6 @@
|
|||||||
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 */,
|
||||||
@ -1508,7 +1427,6 @@
|
|||||||
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 */,
|
||||||
@ -1671,7 +1589,7 @@
|
|||||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 75;
|
CURRENT_PROJECT_VERSION = 72;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
@ -1709,7 +1627,7 @@
|
|||||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 75;
|
CURRENT_PROJECT_VERSION = 72;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// Base Class use to build Controls.
|
/// Base Class use to build Controls.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSControl)
|
@objc(VDSControl)
|
||||||
open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
|
open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -28,6 +28,7 @@ public protocol SelectorControlable: Control, Changeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Base Class used to build out a Selector control.
|
/// Base Class used to build out a Selector control.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSSelectorBase)
|
@objc(VDSSelectorBase)
|
||||||
open class SelectorBase: Control, SelectorControlable, ParentViewProtocol {
|
open class SelectorBase: Control, SelectorControlable, ParentViewProtocol {
|
||||||
|
|
||||||
@ -86,6 +87,9 @@ open class SelectorBase: Control, SelectorControlable, ParentViewProtocol {
|
|||||||
|
|
||||||
open var selectorColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() } }
|
open var selectorColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// The natural size for the receiving view, considering only properties of the view itself.
|
||||||
|
open override var intrinsicContentSize: CGSize { size }
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -105,16 +109,6 @@ open class SelectorBase: Control, SelectorControlable, ParentViewProtocol {
|
|||||||
super.setup()
|
super.setup()
|
||||||
isAccessibilityElement = true
|
isAccessibilityElement = true
|
||||||
accessibilityTraits = .button
|
accessibilityTraits = .button
|
||||||
|
|
||||||
let layoutGuide = UILayoutGuide()
|
|
||||||
addLayoutGuide(layoutGuide)
|
|
||||||
layoutGuide
|
|
||||||
.pinTop(0)
|
|
||||||
.pinLeading(0)
|
|
||||||
.pinTrailing(0, .defaultHigh)
|
|
||||||
.pinBottom(0, .defaultHigh)
|
|
||||||
.width(size.width)
|
|
||||||
.height(size.height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func setDefaults() {
|
open override func setDefaults() {
|
||||||
|
|||||||
@ -43,14 +43,13 @@ open class SelectorItemBase<Selector: SelectorBase>: Control, Errorable, Changea
|
|||||||
|
|
||||||
private var mainStackView = UIStackView().with {
|
private var mainStackView = UIStackView().with {
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
$0.alignment = .fill
|
$0.alignment = .top
|
||||||
$0.axis = .vertical
|
$0.axis = .vertical
|
||||||
}
|
}
|
||||||
|
|
||||||
private var selectorStackView = UIStackView().with {
|
private var selectorStackView = UIStackView().with {
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
$0.alignment = .fill
|
$0.alignment = .top
|
||||||
|
|
||||||
$0.axis = .horizontal
|
$0.axis = .horizontal
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,16 +171,10 @@ open class SelectorItemBase<Selector: SelectorBase>: Control, Errorable, Changea
|
|||||||
isAccessibilityElement = false
|
isAccessibilityElement = false
|
||||||
addSubview(mainStackView)
|
addSubview(mainStackView)
|
||||||
|
|
||||||
//wrap the selectorView in a view that won't stretch it
|
|
||||||
//do this by not pinning the bottom
|
|
||||||
let selectorViewWrapper = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false }
|
|
||||||
selectorViewWrapper.addSubview(selectorView)
|
|
||||||
selectorView.pinTop().pinLeading().pinTrailing().pinBottomLessThanOrEqualTo()
|
|
||||||
|
|
||||||
mainStackView.isUserInteractionEnabled = false
|
mainStackView.isUserInteractionEnabled = false
|
||||||
mainStackView.addArrangedSubview(selectorStackView)
|
mainStackView.addArrangedSubview(selectorStackView)
|
||||||
mainStackView.addArrangedSubview(errorLabel)
|
mainStackView.addArrangedSubview(errorLabel)
|
||||||
selectorStackView.addArrangedSubview(selectorViewWrapper)
|
selectorStackView.addArrangedSubview(selectorView)
|
||||||
selectorStackView.addArrangedSubview(selectorLabelStackView)
|
selectorStackView.addArrangedSubview(selectorLabelStackView)
|
||||||
selectorLabelStackView.addArrangedSubview(label)
|
selectorLabelStackView.addArrangedSubview(label)
|
||||||
selectorLabelStackView.addArrangedSubview(childLabel)
|
selectorLabelStackView.addArrangedSubview(childLabel)
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// Base Class used to build Views.
|
/// Base Class used to build Views.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSView)
|
@objc(VDSView)
|
||||||
open class View: UIView, ViewProtocol, UserInfoable, Clickable {
|
open class View: UIView, ViewProtocol, UserInfoable, Clickable {
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import Combine
|
import Combine
|
||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSAlertViewController)
|
@objc(VDSAlertViewController)
|
||||||
open class AlertViewController: UIViewController, Surfaceable {
|
open class AlertViewController: UIViewController, Surfaceable {
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSClearPopoverViewController)
|
@objc(VDSClearPopoverViewController)
|
||||||
open class ClearPopoverViewController: UIViewController, UIPopoverPresentationControllerDelegate {
|
open class ClearPopoverViewController: UIViewController, UIPopoverPresentationControllerDelegate {
|
||||||
|
|
||||||
|
|||||||
@ -1,63 +0,0 @@
|
|||||||
//
|
|
||||||
// LanguageManager.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Matt Bruce on 9/25/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
// Language Manager to control the current language setting
|
|
||||||
public class LanguageManager {
|
|
||||||
|
|
||||||
// Enum to define supported languages
|
|
||||||
public enum SupportedLanguage: String, CustomStringConvertible {
|
|
||||||
case english = "en"
|
|
||||||
case spanish = "es"
|
|
||||||
|
|
||||||
public var description: String { self == .english ? "English" : "Spanish"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private static variable to hold the in-memory current language
|
|
||||||
private static var _currentLanguage: SupportedLanguage? {
|
|
||||||
didSet {
|
|
||||||
TextStyle.Provider.updateCurrentStyles()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Static property to manage the current language setting
|
|
||||||
public static var currentLanguage: SupportedLanguage {
|
|
||||||
get {
|
|
||||||
// Check if there is an in-memory language setting
|
|
||||||
guard let _currentLanguage else {
|
|
||||||
|
|
||||||
// set default
|
|
||||||
var deviceCurrentLanguage: SupportedLanguage = .english
|
|
||||||
|
|
||||||
// Check device's preferred language
|
|
||||||
let deviceLanguage = Locale.preferredLanguages.first ?? "en"
|
|
||||||
if deviceLanguage.starts(with: "es") {
|
|
||||||
deviceCurrentLanguage = .spanish
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentLanguage = deviceCurrentLanguage
|
|
||||||
return deviceCurrentLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
return _currentLanguage
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
// Set the in-memory language
|
|
||||||
_currentLanguage = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to set language using a language code string
|
|
||||||
public static func setLanguage(with code: String) {
|
|
||||||
if code.starts(with: "es") {
|
|
||||||
_currentLanguage = .spanish
|
|
||||||
} else {
|
|
||||||
_currentLanguage = .english
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -15,6 +15,7 @@ import Combine
|
|||||||
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
||||||
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
||||||
/// to its parent this object will stretch to the parent's width.
|
/// to its parent this object will stretch to the parent's width.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSBadge)
|
@objc(VDSBadge)
|
||||||
open class Badge: View, ParentViewProtocol {
|
open class Badge: View, ParentViewProtocol {
|
||||||
|
|
||||||
@ -37,16 +38,8 @@ open class Badge: View, ParentViewProtocol {
|
|||||||
// MARK: - Enums
|
// MARK: - Enums
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
/// Enum used to describe the primary color for the view.
|
/// Enum used to describe the primary color for the view.
|
||||||
public enum FillColor: Equatable {
|
public enum FillColor: String, CaseIterable {
|
||||||
case red, yellow, green, orange, blue, black, white
|
case red, yellow, green, orange, blue, black, white
|
||||||
case token(UIColor.VDSColor)
|
|
||||||
case custom(UIColor)
|
|
||||||
|
|
||||||
private var reflectedValue: String { String(reflecting: self) }
|
|
||||||
|
|
||||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
|
||||||
lhs.reflectedValue == rhs.reflectedValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -72,8 +65,6 @@ open class Badge: View, ParentViewProtocol {
|
|||||||
/// The text that will be shown in the label.
|
/// The text that will be shown in the label.
|
||||||
open var text: String = "" { didSet { setNeedsUpdate() }}
|
open var text: String = "" { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
open var textColor: TextColor? { didSet { setNeedsUpdate() }}
|
|
||||||
|
|
||||||
/// When applied, this property takes a px value that will restrict the width at that point.
|
/// When applied, this property takes a px value that will restrict the width at that point.
|
||||||
open var maxWidth: CGFloat? { didSet { setNeedsUpdate() }}
|
open var maxWidth: CGFloat? { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
@ -102,91 +93,38 @@ open class Badge: View, ParentViewProtocol {
|
|||||||
right: VDSLayout.space1X)
|
right: VDSLayout.space1X)
|
||||||
|
|
||||||
/// ColorConfiguration that is mapped to the 'fillColor' for the surface.
|
/// ColorConfiguration that is mapped to the 'fillColor' for the surface.
|
||||||
private var backgroundColorConfiguration = SurfaceColorConfiguration()
|
private var backgroundColorConfiguration: AnyColorable = {
|
||||||
|
let config = KeyedColorConfiguration<Badge, FillColor>(keyPath: \.fillColor)
|
||||||
|
config.setSurfaceColors(VDSColor.badgesBackgroundRedOnlight, VDSColor.badgesBackgroundRedOndark, forKey: .red)
|
||||||
|
config.setSurfaceColors(VDSColor.badgesBackgroundYellowOnlight, VDSColor.badgesBackgroundYellowOndark, forKey: .yellow)
|
||||||
|
config.setSurfaceColors(VDSColor.badgesBackgroundGreenOnlight, VDSColor.badgesBackgroundGreenOndark, forKey: .green)
|
||||||
|
config.setSurfaceColors(VDSColor.badgesBackgroundOrangeOnlight, VDSColor.badgesBackgroundOrangeOndark, forKey: .orange)
|
||||||
|
config.setSurfaceColors(VDSColor.badgesBackgroundBlueOnlight, VDSColor.badgesBackgroundBlueOndark, forKey: .blue)
|
||||||
|
config.setSurfaceColors(VDSColor.badgesBackgroundBlackOnlight, VDSColor.badgesBackgroundBlackOndark, forKey: .black)
|
||||||
|
config.setSurfaceColors(VDSColor.badgesBackgroundWhiteOnlight, VDSColor.badgesBackgroundWhiteOndark, forKey: .white)
|
||||||
|
return config.eraseToAnyColorable()
|
||||||
|
}()
|
||||||
|
|
||||||
/// ColorConfiguration for the Text.
|
/// ColorConfiguration for the Text.
|
||||||
private var textColorConfiguration = ViewColorConfiguration()
|
private var textColorConfiguration = ViewColorConfiguration()
|
||||||
|
|
||||||
/// Updates the textColorConfiguration based on the fillColor.
|
/// Updates the textColorConfiguration based on the fillColor.
|
||||||
public func updateColorConfig() {
|
public func updateTextColorConfig() {
|
||||||
var config = backgroundColorConfiguration
|
|
||||||
switch fillColor {
|
|
||||||
case .red:
|
|
||||||
config.lightColor = VDSColor.badgesBackgroundRedOnlight
|
|
||||||
config.darkColor = VDSColor.badgesBackgroundRedOndark
|
|
||||||
case .yellow:
|
|
||||||
config.lightColor = VDSColor.badgesBackgroundYellowOnlight
|
|
||||||
config.darkColor = VDSColor.badgesBackgroundYellowOndark
|
|
||||||
case .green:
|
|
||||||
config.lightColor = VDSColor.badgesBackgroundGreenOnlight
|
|
||||||
config.darkColor = VDSColor.badgesBackgroundGreenOndark
|
|
||||||
case .orange:
|
|
||||||
config.lightColor = VDSColor.badgesBackgroundOrangeOnlight
|
|
||||||
config.darkColor = VDSColor.badgesBackgroundOrangeOndark
|
|
||||||
case .blue:
|
|
||||||
config.lightColor = VDSColor.badgesBackgroundBlueOnlight
|
|
||||||
config.darkColor = VDSColor.badgesBackgroundBlueOndark
|
|
||||||
case .black:
|
|
||||||
config.lightColor = VDSColor.badgesBackgroundBlackOnlight
|
|
||||||
config.darkColor = VDSColor.badgesBackgroundBlackOndark
|
|
||||||
case .white:
|
|
||||||
config.lightColor = VDSColor.badgesBackgroundWhiteOnlight
|
|
||||||
config.darkColor = VDSColor.badgesBackgroundWhiteOndark
|
|
||||||
case .token(let color):
|
|
||||||
config.lightColor = color.uiColor
|
|
||||||
config.darkColor = color.uiColor
|
|
||||||
case .custom(let color):
|
|
||||||
config.lightColor = color
|
|
||||||
config.darkColor = color
|
|
||||||
}
|
|
||||||
|
|
||||||
textColorConfiguration.reset()
|
textColorConfiguration.reset()
|
||||||
|
|
||||||
func update(for color: UIColor) {
|
switch fillColor {
|
||||||
if let configuration = textColor?.configuration {
|
|
||||||
textColorConfiguration = configuration
|
|
||||||
} else {
|
|
||||||
if color.isDark() {
|
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
|
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true)
|
|
||||||
} else {
|
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
|
||||||
|
|
||||||
}
|
case .red, .black:
|
||||||
}
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
|
||||||
}
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true)
|
||||||
|
|
||||||
if let textColor {
|
case .yellow, .white:
|
||||||
switch textColor {
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||||
case .token(let color):
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||||
textColorConfiguration.setSurfaceColors(color.uiColor, color.uiColor, forDisabled: false)
|
|
||||||
textColorConfiguration.setSurfaceColors(color.uiColor, color.uiColor, forDisabled: true)
|
|
||||||
case .custom(let color):
|
|
||||||
textColorConfiguration.setSurfaceColors(color, color, forDisabled: false)
|
|
||||||
textColorConfiguration.setSurfaceColors(color, color, forDisabled: true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch fillColor {
|
|
||||||
|
|
||||||
case .red, .black:
|
case .orange, .green, .blue:
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true)
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||||
|
|
||||||
case .yellow, .white:
|
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
|
||||||
|
|
||||||
case .orange, .green, .blue:
|
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
|
||||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
|
||||||
|
|
||||||
case .token(let color):
|
|
||||||
update(for: color.uiColor)
|
|
||||||
|
|
||||||
case .custom(let color):
|
|
||||||
update(for: color)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +179,7 @@ open class Badge: View, ParentViewProtocol {
|
|||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
super.updateView()
|
super.updateView()
|
||||||
|
|
||||||
updateColorConfig()
|
updateTextColorConfig()
|
||||||
updateMaxWidth()
|
updateMaxWidth()
|
||||||
|
|
||||||
backgroundColor = backgroundColorConfiguration.getColor(self)
|
backgroundColor = backgroundColorConfiguration.getColor(self)
|
||||||
@ -253,29 +191,3 @@ open class Badge: View, ParentViewProtocol {
|
|||||||
label.isEnabled = isEnabled
|
label.isEnabled = isEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Badge{
|
|
||||||
public enum TextColor: Equatable {
|
|
||||||
case token(UIColor.VDSColor)
|
|
||||||
case custom(UIColor)
|
|
||||||
|
|
||||||
private var reflectedValue: String { String(reflecting: self) }
|
|
||||||
|
|
||||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
|
||||||
lhs.reflectedValue == rhs.reflectedValue
|
|
||||||
}
|
|
||||||
|
|
||||||
public var configuration: ViewColorConfiguration {
|
|
||||||
let config = ViewColorConfiguration()
|
|
||||||
switch self {
|
|
||||||
case .token(let color):
|
|
||||||
config.setSurfaceColors(color.uiColor, color.uiColor, forDisabled: true)
|
|
||||||
config.setSurfaceColors(color.uiColor, color.uiColor, forDisabled: false)
|
|
||||||
case .custom(let color):
|
|
||||||
config.setSurfaceColors(color, color, forDisabled: true)
|
|
||||||
config.setSurfaceColors(color, color, forDisabled: false)
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// A badge indicator is a visual label used to convey status or highlight supplemental information.
|
/// A badge indicator is a visual label used to convey status or highlight supplemental information.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSBadgeIndicator)
|
@objc(VDSBadgeIndicator)
|
||||||
open class BadgeIndicator: View, ParentViewProtocol {
|
open class BadgeIndicator: View, ParentViewProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import Combine
|
|||||||
/// A Breadcrumb Item contains href(link) and selected flag.
|
/// A Breadcrumb Item contains href(link) and selected flag.
|
||||||
/// Breadcrumb links to its respective page if it is not disabled.
|
/// Breadcrumb links to its respective page if it is not disabled.
|
||||||
/// Breadcrumb contains text with a separator by default, highlights text in bold without a separator if selected.
|
/// Breadcrumb contains text with a separator by default, highlights text in bold without a separator if selected.
|
||||||
|
@objcMembers
|
||||||
@objc (VDSBreadcrumbItem)
|
@objc (VDSBreadcrumbItem)
|
||||||
open class BreadcrumbItem: ButtonBase {
|
open class BreadcrumbItem: ButtonBase {
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import Combine
|
|||||||
/// A Breadcrumbs contains BreadcrumbItems.
|
/// A Breadcrumbs contains BreadcrumbItems.
|
||||||
/// It contains Breadcrumb Item Default, Breadcrumb Item Selected, Separator.
|
/// It contains Breadcrumb Item Default, Breadcrumb Item Selected, Separator.
|
||||||
/// Breadcrumbs are secondary navigation that use a hierarchy of internal links to tell customers where they are in an experience. Each breadcrumb links to its respective page, except for that of current page.
|
/// Breadcrumbs are secondary navigation that use a hierarchy of internal links to tell customers where they are in an experience. Each breadcrumb links to its respective page, except for that of current page.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSBreadcrumbs)
|
@objc(VDSBreadcrumbs)
|
||||||
open class Breadcrumbs: View, ParentViewProtocol {
|
open class Breadcrumbs: View, ParentViewProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import Combine
|
|||||||
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
||||||
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
||||||
/// to its parent this object will stretch to the parent's width.
|
/// to its parent this object will stretch to the parent's width.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSButton)
|
@objc(VDSButton)
|
||||||
open class Button: ButtonBase, Useable {
|
open class Button: ButtonBase, Useable {
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// Base class used for UIButton type classes.
|
/// Base class used for UIButton type classes.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSButtonBase)
|
@objc(VDSButtonBase)
|
||||||
open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
|
open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// A button group contains combinations of related CTAs including ``Button``, ``TextLink``, and ``TextLinkCaret``. This group component controls a combination's orientation, spacing, size and allowable size pairings.
|
/// A button group contains combinations of related CTAs including ``Button``, ``TextLink``, and ``TextLinkCaret``. This group component controls a combination's orientation, spacing, size and allowable size pairings.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSButtonGroup)
|
@objc(VDSButtonGroup)
|
||||||
open class ButtonGroup: View {
|
open class ButtonGroup: View {
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import Combine
|
|||||||
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
||||||
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
||||||
/// to its parent this object will stretch to the parent's width.
|
/// to its parent this object will stretch to the parent's width.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTextLink)
|
@objc(VDSTextLink)
|
||||||
open class TextLink: ButtonBase {
|
open class TextLink: ButtonBase {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import Combine
|
|||||||
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
||||||
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
||||||
/// to its parent this object will stretch to the parent's width.
|
/// to its parent this object will stretch to the parent's width.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTextLinkCaret)
|
@objc(VDSTextLinkCaret)
|
||||||
open class TextLinkCaret: ButtonBase {
|
open class TextLinkCaret: ButtonBase {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// A calendar is a monthly view that lets customers select a single date.
|
/// A calendar is a monthly view that lets customers select a single date.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSCalendar)
|
@objc(VDSCalendar)
|
||||||
open class CalendarBase: Control, Changeable {
|
open class CalendarBase: Control, Changeable {
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import Combine
|
|||||||
|
|
||||||
/// A carousel is a collection of related content in a row that a customer can navigate through horizontally.
|
/// A carousel is a collection of related content in a row that a customer can navigate through horizontally.
|
||||||
/// Use this component to show content that is supplementary, not essential for task completion.
|
/// Use this component to show content that is supplementary, not essential for task completion.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSCarousel)
|
@objc(VDSCarousel)
|
||||||
open class Carousel: View {
|
open class Carousel: View {
|
||||||
|
|
||||||
@ -153,38 +154,27 @@ open class Carousel: View {
|
|||||||
$0.backgroundColor = .clear
|
$0.backgroundColor = .clear
|
||||||
}
|
}
|
||||||
|
|
||||||
private lazy var collectionView: UICollectionView = {
|
private var scrollView = UIScrollView().with {
|
||||||
let layout = UICollectionViewFlowLayout()
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
layout.scrollDirection = .horizontal
|
$0.backgroundColor = .clear
|
||||||
let collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
|
}
|
||||||
collectionView.isScrollEnabled = true
|
|
||||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
collectionView.delegate = self
|
|
||||||
collectionView.dataSource = self
|
|
||||||
collectionView.showsHorizontalScrollIndicator = false
|
|
||||||
collectionView.showsVerticalScrollIndicator = false
|
|
||||||
collectionView.backgroundColor = .clear
|
|
||||||
collectionView.register(CarouselSlotCell.self,
|
|
||||||
forCellWithReuseIdentifier: CarouselSlotCell.identifier)
|
|
||||||
return collectionView
|
|
||||||
}()
|
|
||||||
|
|
||||||
/// Previous button to show previous slide.
|
/// Previous button to show previous slide.
|
||||||
private var previousButton = ButtonIcon().with {
|
private var previousButton = ButtonIcon().with {
|
||||||
$0.kind = .lowContrast
|
$0.kind = .lowContrast
|
||||||
$0.iconName = .paginationLeftCaret
|
$0.iconName = .leftCaret
|
||||||
$0.iconOffset = .init(x: -2, y: 0)
|
$0.iconOffset = .init(x: -2, y: 0)
|
||||||
$0.customContainerSize = UIDevice.isIPad ? 40 : 28
|
$0.customContainerSize = UIDevice.isIPad ? 40 : 28
|
||||||
$0.customIconSize = UIDevice.isIPad ? 16 : 12
|
$0.icon.customSize = UIDevice.isIPad ? 16 : 12
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Next button to show next slide.
|
/// Next button to show next slide.
|
||||||
private var nextButton = ButtonIcon().with {
|
private var nextButton = ButtonIcon().with {
|
||||||
$0.kind = .lowContrast
|
$0.kind = .lowContrast
|
||||||
$0.iconName = .paginationRightCaret
|
$0.iconName = .rightCaret
|
||||||
$0.iconOffset = .init(x: 2, y: 0)
|
$0.iconOffset = .init(x: 2, y: 0)
|
||||||
$0.customContainerSize = UIDevice.isIPad ? 40 : 28
|
$0.customContainerSize = UIDevice.isIPad ? 40 : 28
|
||||||
$0.customIconSize = UIDevice.isIPad ? 16 : 12
|
$0.icon.customSize = UIDevice.isIPad ? 16 : 12
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A publisher for when moving the carousel. Passes parameters selectedGroupIndex (position).
|
/// A publisher for when moving the carousel. Passes parameters selectedGroupIndex (position).
|
||||||
@ -225,8 +215,8 @@ open class Carousel: View {
|
|||||||
containerView.addSubview(contentStackView)
|
containerView.addSubview(contentStackView)
|
||||||
|
|
||||||
// Add scrollview
|
// Add scrollview
|
||||||
scrollContainerView.addSubview(collectionView)
|
scrollContainerView.addSubview(scrollView)
|
||||||
collectionView.pinToSuperView()
|
scrollView.pinToSuperView()
|
||||||
|
|
||||||
// Add pagination button icons
|
// Add pagination button icons
|
||||||
scrollContainerView.addSubview(previousButton)
|
scrollContainerView.addSubview(previousButton)
|
||||||
@ -269,25 +259,14 @@ open class Carousel: View {
|
|||||||
/// Used to make changes to the View based off a change events or from local properties.
|
/// Used to make changes to the View based off a change events or from local properties.
|
||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
super.updateView()
|
super.updateView()
|
||||||
updateScrollbar()
|
|
||||||
updateCarousel()
|
|
||||||
collectionView.collectionViewLayout.invalidateLayout()
|
|
||||||
collectionView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Private Methods
|
|
||||||
//--------------------------------------------------
|
|
||||||
private func updateScrollbar() {
|
|
||||||
carouselScrollBar.numberOfSlides = views.count
|
carouselScrollBar.numberOfSlides = views.count
|
||||||
carouselScrollBar.layout = layout
|
carouselScrollBar.layout = layout
|
||||||
if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) {
|
if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) {
|
||||||
carouselScrollBar.position = 1
|
carouselScrollBar.position = 1
|
||||||
}
|
}
|
||||||
carouselScrollBar.isHidden = (totalPositions() <= 1) ? true : false
|
carouselScrollBar.isHidden = (totalPositions() <= 1) ? true : false
|
||||||
}
|
|
||||||
|
|
||||||
private func updateCarousel() {
|
|
||||||
// Mobile/Tablet layouts without peek - must show pagination controls.
|
// Mobile/Tablet layouts without peek - must show pagination controls.
|
||||||
// If peek is ‘none’, pagination controls should show. So set to persistent.
|
// If peek is ‘none’, pagination controls should show. So set to persistent.
|
||||||
if peek == .none {
|
if peek == .none {
|
||||||
@ -305,9 +284,12 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatePaginationControls()
|
updatePaginationControls()
|
||||||
updateContainerHeight()
|
addCarouselSlots()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Private Methods
|
||||||
|
//--------------------------------------------------
|
||||||
private func addlisteners() {
|
private func addlisteners() {
|
||||||
nextButton.onClick = { _ in self.nextButtonClick() }
|
nextButton.onClick = { _ in self.nextButtonClick() }
|
||||||
previousButton.onClick = { _ in self.previousButtonClick() }
|
previousButton.onClick = { _ in self.previousButtonClick() }
|
||||||
@ -383,13 +365,47 @@ open class Carousel: View {
|
|||||||
return height
|
return height
|
||||||
}
|
}
|
||||||
|
|
||||||
// update carousel size and load data if any
|
// Add carousel slots and load data if any
|
||||||
private func updateContainerHeight() {
|
private func addCarouselSlots() {
|
||||||
getSlotWidth()
|
getSlotWidth()
|
||||||
if containerView.frame.size.width > 0 {
|
if containerView.frame.size.width > 0 {
|
||||||
containerViewHeightConstraint?.isActive = false
|
containerViewHeightConstraint?.isActive = false
|
||||||
containerStackHeightConstraint?.isActive = false
|
containerStackHeightConstraint?.isActive = false
|
||||||
let slotHeight = fetchCarouselHeight()
|
let slotHeight = fetchCarouselHeight()
|
||||||
|
|
||||||
|
// Perform a loop to iterate each subView
|
||||||
|
scrollView.subviews.forEach { subView in
|
||||||
|
// Removing subView from its parent view
|
||||||
|
subView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add carousel items
|
||||||
|
if views.count > 0 {
|
||||||
|
var xPos = 0.0
|
||||||
|
for index in 0...views.count - 1 {
|
||||||
|
|
||||||
|
// Add Carousel Slot
|
||||||
|
let carouselSlot = View().with {
|
||||||
|
$0.clipsToBounds = true
|
||||||
|
}
|
||||||
|
scrollView.addSubview(carouselSlot)
|
||||||
|
scrollView.delegate = self
|
||||||
|
|
||||||
|
carouselSlot
|
||||||
|
.pinTop()
|
||||||
|
.pinBottom()
|
||||||
|
.pinLeading(xPos)
|
||||||
|
.width(minimumSlotWidth)
|
||||||
|
.height(slotHeight)
|
||||||
|
xPos = xPos + minimumSlotWidth + gutter.value
|
||||||
|
|
||||||
|
let component = views[index]
|
||||||
|
carouselSlot.addSubview(component)
|
||||||
|
setSlotAlignment(contentView: component)
|
||||||
|
}
|
||||||
|
scrollView.contentSize = CGSize(width: xPos - gutter.value, height: slotHeight)
|
||||||
|
}
|
||||||
|
|
||||||
let containerHeight = slotHeight + scrollbarTopSpace + containerSize.height
|
let containerHeight = slotHeight + scrollbarTopSpace + containerSize.height
|
||||||
if carouselScrollBar.isHidden {
|
if carouselScrollBar.isHidden {
|
||||||
containerStackHeightConstraint = contentStackView.heightAnchor.constraint(equalToConstant: slotHeight)
|
containerStackHeightConstraint = contentStackView.heightAnchor.constraint(equalToConstant: slotHeight)
|
||||||
@ -403,6 +419,43 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set slot alignment if provided. Used only when slot content have different heights or widths.
|
||||||
|
private func setSlotAlignment(contentView: UIView) {
|
||||||
|
switch slotAlignment?.vertical {
|
||||||
|
case .top:
|
||||||
|
contentView
|
||||||
|
.pinTop()
|
||||||
|
.pinBottomLessThanOrEqualTo()
|
||||||
|
case .middle:
|
||||||
|
contentView
|
||||||
|
.pinTopGreaterThanOrEqualTo()
|
||||||
|
.pinBottomLessThanOrEqualTo()
|
||||||
|
.pinCenterY()
|
||||||
|
case .bottom:
|
||||||
|
contentView
|
||||||
|
.pinTopGreaterThanOrEqualTo()
|
||||||
|
.pinBottom()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch slotAlignment?.horizontal {
|
||||||
|
case .left:
|
||||||
|
contentView
|
||||||
|
.pinLeading()
|
||||||
|
.pinTrailingLessThanOrEqualTo()
|
||||||
|
case .center:
|
||||||
|
contentView
|
||||||
|
.pinLeadingGreaterThanOrEqualTo()
|
||||||
|
.pinTrailingLessThanOrEqualTo()
|
||||||
|
.pinCenterX()
|
||||||
|
case .right:
|
||||||
|
contentView
|
||||||
|
.pinLeadingGreaterThanOrEqualTo()
|
||||||
|
.pinTrailing()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the slot width relative to the peak
|
// Get the slot width relative to the peak
|
||||||
private func getSlotWidth() {
|
private func getSlotWidth() {
|
||||||
let actualWidth = containerView.frame.size.width
|
let actualWidth = containerView.frame.size.width
|
||||||
@ -452,7 +505,7 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateScrollbarPosition(targetContentOffsetXPos:CGFloat) {
|
private func updateScrollbarPosition(targetContentOffsetXPos:CGFloat) {
|
||||||
let scrollContentSizeWidth = collectionView.contentSize.width
|
let scrollContentSizeWidth = scrollView.contentSize.width
|
||||||
let totalPositions = totalPositions()
|
let totalPositions = totalPositions()
|
||||||
let layoutSpace = Int (floor( Double(scrollContentSizeWidth / Double(totalPositions))))
|
let layoutSpace = Int (floor( Double(scrollContentSizeWidth / Double(totalPositions))))
|
||||||
let remindSpace = Int(targetContentOffsetXPos) % layoutSpace
|
let remindSpace = Int(targetContentOffsetXPos) % layoutSpace
|
||||||
@ -462,11 +515,10 @@ open class Carousel: View {
|
|||||||
updateScrollPosition(position: contentPos, callbackText: "ScrollViewMoved")
|
updateScrollPosition(position: contentPos, callbackText: "ScrollViewMoved")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update collectionview offset relative to scrollbar thumb position
|
// Update scrollview offset relative to scrollbar thumb position
|
||||||
private func updateScrollPosition(position: Int, callbackText: String) {
|
private func updateScrollPosition(position: Int, callbackText: String) {
|
||||||
if carouselScrollBar.numberOfSlides > 0 {
|
if carouselScrollBar.numberOfSlides > 0 {
|
||||||
let scrollContentSizeWidth = collectionView.contentSize.width
|
let scrollContentSizeWidth = scrollView.contentSize.width
|
||||||
|
|
||||||
let totalPositions = totalPositions()
|
let totalPositions = totalPositions()
|
||||||
var xPos = 0.0
|
var xPos = 0.0
|
||||||
if position == 1 {
|
if position == 1 {
|
||||||
@ -484,8 +536,8 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
carouselScrollBar.scrubberId = position+1
|
carouselScrollBar.scrubberId = position+1
|
||||||
let yPos = collectionView.contentOffset.y
|
let yPos = scrollView.contentOffset.y
|
||||||
collectionView.setContentOffset(CGPoint(x: xPos, y: yPos), animated: true)
|
scrollView.setContentOffset(CGPoint(x: xPos, y: yPos), animated: true)
|
||||||
showPaginationControls()
|
showPaginationControls()
|
||||||
groupIndex = position-1
|
groupIndex = position-1
|
||||||
onChangePublisher.send(groupIndex)
|
onChangePublisher.send(groupIndex)
|
||||||
@ -505,35 +557,5 @@ extension Carousel: UIScrollViewDelegate {
|
|||||||
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
||||||
updateScrollbarPosition(targetContentOffsetXPos: targetContentOffset.pointee.x)
|
updateScrollbarPosition(targetContentOffsetXPos: targetContentOffset.pointee.x)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
extension Carousel: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - UICollectionView Delegate & Datasource
|
|
||||||
//--------------------------------------------------
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
|
||||||
views.count
|
|
||||||
}
|
|
||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
|
||||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CarouselSlotCell.identifier, for: indexPath) as? CarouselSlotCell else { return UICollectionViewCell() }
|
|
||||||
let component = views[indexPath.row]
|
|
||||||
cell.update(with: component, slotAlignment: slotAlignment, surface: surface)
|
|
||||||
cell.layoutIfNeeded()
|
|
||||||
//component.setNeedsLayout()
|
|
||||||
if hasDebugBorder {
|
|
||||||
cell.addDebugBorder()
|
|
||||||
} else {
|
|
||||||
cell.removeDebugBorder()
|
|
||||||
}
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
|
|
||||||
return gutter.value
|
|
||||||
}
|
|
||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
|
||||||
return CGSize(width: minimumSlotWidth, height: fetchCarouselHeight())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,85 +0,0 @@
|
|||||||
//
|
|
||||||
// CarouselSlotCell.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Kanamarlapudi, Vasavi on 23/08/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
final class CarouselSlotCell: UICollectionViewCell {
|
|
||||||
|
|
||||||
///Identifier for the Calendar Date Cell.
|
|
||||||
static let identifier: String = String(describing: CarouselSlotCell.self)
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Initializers
|
|
||||||
//--------------------------------------------------
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
setUp()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
setUp()
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Private Methods
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
/// Configuring the cell with default setup.
|
|
||||||
private func setUp() {
|
|
||||||
isAccessibilityElement = true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updating UI based on data along with surface.
|
|
||||||
func update(with component: UIView, slotAlignment: Carousel.CarouselSlotAlignmentModel?, surface: Surface) {
|
|
||||||
contentView.subviews.forEach { $0.removeFromSuperview() }
|
|
||||||
contentView.addSubview(component)
|
|
||||||
if var surfacedView = component as? Surfaceable {
|
|
||||||
surfacedView.surface = surface
|
|
||||||
}
|
|
||||||
setSlotAlignment(alignment: slotAlignment, contentView: component)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set slot alignment if provided. Used only when slot content have different heights or widths.
|
|
||||||
private func setSlotAlignment(alignment: Carousel.CarouselSlotAlignmentModel?, contentView: UIView) {
|
|
||||||
switch alignment?.vertical {
|
|
||||||
case .top:
|
|
||||||
contentView
|
|
||||||
.pinTop()
|
|
||||||
.pinBottomLessThanOrEqualTo()
|
|
||||||
case .middle:
|
|
||||||
contentView
|
|
||||||
.pinTopGreaterThanOrEqualTo()
|
|
||||||
.pinBottomLessThanOrEqualTo()
|
|
||||||
.pinCenterY()
|
|
||||||
case .bottom:
|
|
||||||
contentView
|
|
||||||
.pinTopGreaterThanOrEqualTo()
|
|
||||||
.pinBottom()
|
|
||||||
default: break
|
|
||||||
}
|
|
||||||
|
|
||||||
switch alignment?.horizontal {
|
|
||||||
case .left:
|
|
||||||
contentView
|
|
||||||
.pinLeading()
|
|
||||||
.pinTrailingLessThanOrEqualTo()
|
|
||||||
case .center:
|
|
||||||
contentView
|
|
||||||
.pinLeadingGreaterThanOrEqualTo()
|
|
||||||
.pinTrailingLessThanOrEqualTo()
|
|
||||||
.pinCenterX()
|
|
||||||
case .right:
|
|
||||||
contentView
|
|
||||||
.pinLeadingGreaterThanOrEqualTo()
|
|
||||||
.pinTrailing()
|
|
||||||
default: break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -12,6 +12,7 @@ import Combine
|
|||||||
|
|
||||||
/// A carousel scrollbar is a control that allows to navigate between items in a carousel.
|
/// A carousel scrollbar is a control that allows to navigate between items in a carousel.
|
||||||
/// It's also a status indicator that conveys the relative amount of content in a carousel and a location within it.
|
/// It's also a status indicator that conveys the relative amount of content in a carousel and a location within it.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSCarouselScrollbar)
|
@objc(VDSCarouselScrollbar)
|
||||||
open class CarouselScrollbar: View {
|
open class CarouselScrollbar: View {
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import VDSCoreTokens
|
|||||||
|
|
||||||
/// Checkboxes are a multi-select component through which a customer indicates a choice. This is also used within
|
/// Checkboxes are a multi-select component through which a customer indicates a choice. This is also used within
|
||||||
/// ``CheckboxItem`` and ``CheckboxGroup``
|
/// ``CheckboxItem`` and ``CheckboxGroup``
|
||||||
|
@objcMembers
|
||||||
@objc(VDSCheckbox)
|
@objc(VDSCheckbox)
|
||||||
open class Checkbox: SelectorBase {
|
open class Checkbox: SelectorBase {
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import VDSCoreTokens
|
|||||||
/// When the choice has multiple options, use a checkbox group. For example, use a checkbox group when
|
/// When the choice has multiple options, use a checkbox group. For example, use a checkbox group when
|
||||||
/// asking a customer which attributes they would like to filter their search by. This uses ``CheckboxItem``
|
/// asking a customer which attributes they would like to filter their search by. This uses ``CheckboxItem``
|
||||||
/// to allow user selection.
|
/// to allow user selection.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSCheckboxGroup)
|
@objc(VDSCheckboxGroup)
|
||||||
open class CheckboxGroup: SelectorGroupBase<CheckboxItem>, SelectorGroupMultiSelect {
|
open class CheckboxGroup: SelectorGroupBase<CheckboxItem>, SelectorGroupMultiSelect {
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
/// Checkboxes are a multi-select component through which a customer indicates a choice. If a binary choice, the component is a checkbox. If the choice has multiple options, the component is a ``CheckboxGroup``.
|
/// Checkboxes are a multi-select component through which a customer indicates a choice. If a binary choice, the component is a checkbox. If the choice has multiple options, the component is a ``CheckboxGroup``.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSCheckboxItem)
|
@objc(VDSCheckboxItem)
|
||||||
open class CheckboxItem: SelectorItemBase<Checkbox> {
|
open class CheckboxItem: SelectorItemBase<Checkbox> {
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection.
|
/// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSDatePicker)
|
@objc(VDSDatePicker)
|
||||||
open class DatePicker: EntryFieldBase<String> {
|
open class DatePicker: EntryFieldBase<String> {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -182,15 +183,6 @@ open class DatePicker: EntryFieldBase<String> {
|
|||||||
showPopover()
|
showPopover()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
containerView.accessibilityTraits = [.button]
|
|
||||||
|
|
||||||
containerView.bridge_accessibilityHintBlock = { [weak self] in
|
|
||||||
guard let self else { return "" }
|
|
||||||
return isReadOnly || !isEnabled
|
|
||||||
? ""
|
|
||||||
: isCalendarShowing ? "Expanded, Double tap to close" : "Collapsed, \(accessibilityHintText)"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func getFieldContainer() -> UIView {
|
open override func getFieldContainer() -> UIView {
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection.
|
/// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSDropdownSelect)
|
@objc(VDSDropdownSelect)
|
||||||
open class DropdownSelect: EntryFieldBase<String> {
|
open class DropdownSelect: EntryFieldBase<String> {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -60,9 +61,8 @@ open class DropdownSelect: EntryFieldBase<String> {
|
|||||||
internal var minWidthInlineLabel = 102.0
|
internal var minWidthInlineLabel = 102.0
|
||||||
internal override var minWidth: CGFloat { showInlineLabel ? minWidthInlineLabel : minWidthDefault }
|
internal override var minWidth: CGFloat { showInlineLabel ? minWidthInlineLabel : minWidthDefault }
|
||||||
internal override var maxWidth: CGFloat {
|
internal override var maxWidth: CGFloat {
|
||||||
let frameWidth = constrainedWidth
|
let frameWidth = frame.size.width
|
||||||
let halfWidth = (frameWidth - horizontalStackView.spacing) / 2
|
return helperTextPlacement == .right ? (frameWidth - horizontalStackView.spacing) / 2 : frameWidth
|
||||||
return helperTextPlacement == .right && halfWidth > minWidth * 2 ? halfWidth : frameWidth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The is used for the for adding the helperLabel to the right of the containerView.
|
/// The is used for the for adding the helperLabel to the right of the containerView.
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
MM/DD/YYYY
|
|
||||||
----------------
|
|
||||||
Initial Brand 3.0 handoff
|
|
||||||
|
|
||||||
12/18/2023
|
|
||||||
----------------
|
|
||||||
- New
|
|
||||||
|
|
||||||
12/28/2023
|
|
||||||
----------------
|
|
||||||
- hideSymbol updated to showSymbol and default set to True.
|
|
||||||
- Figma-only properties section added in Footnote Item Configurations section.
|
|
||||||
|
|
||||||
01/16/2024
|
|
||||||
----------------
|
|
||||||
- hideSymbol reverted to hideSymbol and default set to False.
|
|
||||||
- Figma-only properties section removed.
|
|
||||||
@ -1,165 +0,0 @@
|
|||||||
//
|
|
||||||
// FootnoteGroup.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Kanamarlapudi, Vasavi on 29/08/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import VDSCoreTokens
|
|
||||||
|
|
||||||
/// This must always be paired with one or more ``Footnote`` in a FootnoteGroup.
|
|
||||||
@objc(VDSFootnoteGroup)
|
|
||||||
open class FootnoteGroup: View {
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// 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: - enums
|
|
||||||
//--------------------------------------------------
|
|
||||||
/// Enum used to describe the width of a fixed value or percentage of parent's width.
|
|
||||||
public enum Width {
|
|
||||||
case percentage(CGFloat)
|
|
||||||
case value(CGFloat)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Public Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
/// Array of ``Footnote`` for the Footnote items.
|
|
||||||
open var footnoteItems: [FootnoteItem] = [] { didSet { updateFootnoteItems() } }
|
|
||||||
|
|
||||||
/// Any percentage or pixel value and cannot exceed container size.
|
|
||||||
/// If there is a width that is larger than container size, the footnote will resize to container's width.
|
|
||||||
open var width: Width? {
|
|
||||||
get { _width }
|
|
||||||
set {
|
|
||||||
if let newValue {
|
|
||||||
switch newValue {
|
|
||||||
case .percentage(let percentage):
|
|
||||||
if percentage <= 100.0 {
|
|
||||||
_width = newValue
|
|
||||||
}
|
|
||||||
case .value(let value):
|
|
||||||
if value > 0 {
|
|
||||||
_width = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_width = nil
|
|
||||||
}
|
|
||||||
updateContainerWidth()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Private Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
private var _width: Width? = nil
|
|
||||||
|
|
||||||
private lazy var stackView = UIStackView().with {
|
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
$0.axis = .vertical
|
|
||||||
$0.distribution = .fill
|
|
||||||
$0.spacing = VDSLayout.space3X
|
|
||||||
$0.backgroundColor = .clear
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Configuration Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
internal var maxWidth: CGFloat { constrainedWidth }
|
|
||||||
internal var minWidth: CGFloat { containerSize.width }
|
|
||||||
internal var containerSize: CGSize { CGSize(width: 55, height: 44) }
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Constraints
|
|
||||||
//--------------------------------------------------
|
|
||||||
internal var widthConstraint: 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()
|
|
||||||
|
|
||||||
// add footnote item stackview.
|
|
||||||
addSubview(stackView)
|
|
||||||
stackView.pinToSuperView()
|
|
||||||
widthConstraint = widthAnchor.constraint(equalToConstant: 0).deactivate()
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setDefaults() {
|
|
||||||
super.setDefaults()
|
|
||||||
width = nil
|
|
||||||
footnoteItems = []
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to make changes to the View based off a change events or from local properties.
|
|
||||||
open override func updateView() {
|
|
||||||
super.updateView()
|
|
||||||
updateFootnoteItems()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal func updateFootnoteItems() {
|
|
||||||
// symbol containers are as wide as the widest symbol container in the group.
|
|
||||||
var symbolMaxWidth = 0.0
|
|
||||||
|
|
||||||
footnoteItems.forEach { footnote in
|
|
||||||
let separatorWidth = Label().with {
|
|
||||||
$0.text = footnote.symbolType
|
|
||||||
$0.textStyle = footnote.symbolLabel.textStyle
|
|
||||||
$0.sizeToFit()
|
|
||||||
}.intrinsicContentSize.width
|
|
||||||
symbolMaxWidth = max(separatorWidth, symbolMaxWidth)
|
|
||||||
}
|
|
||||||
|
|
||||||
stackView.removeArrangedSubviews()
|
|
||||||
|
|
||||||
// add symbol label, text label to stack.
|
|
||||||
footnoteItems.forEach { footnote in
|
|
||||||
footnote.symbolWidth = symbolMaxWidth
|
|
||||||
footnote.surface = surface
|
|
||||||
stackView.addArrangedSubview(footnote)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update container width after updating content.
|
|
||||||
internal func updateContainerWidth() {
|
|
||||||
var newWidth = 0.0
|
|
||||||
|
|
||||||
switch width {
|
|
||||||
case .percentage(let percentage):
|
|
||||||
newWidth = max(maxWidth * ((percentage) / 100), minWidth)
|
|
||||||
|
|
||||||
case .value(let value):
|
|
||||||
newWidth = value > maxWidth ? maxWidth : value
|
|
||||||
|
|
||||||
case nil: break
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
widthConstraint?.deactivate()
|
|
||||||
|
|
||||||
if newWidth > minWidth && newWidth < maxWidth {
|
|
||||||
widthConstraint?.constant = newWidth
|
|
||||||
widthConstraint?.activate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,256 +0,0 @@
|
|||||||
//
|
|
||||||
// Footnote.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Kanamarlapudi, Vasavi on 21/08/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import VDSCoreTokens
|
|
||||||
|
|
||||||
/// A footnote is text that provides supporting details, legal copy and links to related content.
|
|
||||||
/// It exists at the bottom or "foot" of a page or section.
|
|
||||||
@objc(VDSFootnoteItem)
|
|
||||||
open class FootnoteItem: View {
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// 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: - enums
|
|
||||||
//--------------------------------------------------
|
|
||||||
/// Enum used to describe the kind of component.
|
|
||||||
public enum Kind: String, DefaultValuing, CaseIterable {
|
|
||||||
case primary, secondary
|
|
||||||
|
|
||||||
/// The default kind is 'primary'.
|
|
||||||
public static var defaultValue : Self { .secondary }
|
|
||||||
|
|
||||||
/// Color configuation to Symbol and Text relative to kind.
|
|
||||||
public var colorConfiguration: SurfaceColorConfiguration {
|
|
||||||
switch self {
|
|
||||||
case .primary:
|
|
||||||
return SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark)
|
|
||||||
case .secondary:
|
|
||||||
return SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enum that represents the size availble for component.
|
|
||||||
public enum Size: String, DefaultValuing, CaseIterable {
|
|
||||||
case micro
|
|
||||||
case small
|
|
||||||
case large
|
|
||||||
|
|
||||||
public static var defaultValue: Self { .micro }
|
|
||||||
|
|
||||||
/// TextStyle relative to Size.
|
|
||||||
public var textStyle: TextStyle.StandardStyle {
|
|
||||||
switch self {
|
|
||||||
case .micro:
|
|
||||||
return .micro
|
|
||||||
case .small:
|
|
||||||
return .bodySmall
|
|
||||||
case .large:
|
|
||||||
return .bodyLarge
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enum used to describe the width of a fixed value or percentage of parent's width.
|
|
||||||
public enum Width {
|
|
||||||
case percentage(CGFloat)
|
|
||||||
case value(CGFloat)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Public Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
/// Color to the component. The default kind is Secondary.
|
|
||||||
open var kind: Kind = .defaultValue { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
/// Size of the component. The default size is Micro.
|
|
||||||
open var size: Size = .defaultValue { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
/// If hideSymbol true, the component will show text without symbol.
|
|
||||||
open var hideSymbol: Bool = false { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
/// symbol type will be shown for the footnote item. The default symbolType is 'asterisk'.
|
|
||||||
open var symbolType: String = "*" { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
/// Text of the footnote item.
|
|
||||||
open var text: String? { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
open var tooltipModel: Tooltip.TooltipModel? { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
/// Any percentage or pixel value and cannot exceed container size.
|
|
||||||
/// If there is a width that is larger than container size, the footnote will resize to container's width.
|
|
||||||
open var width: Width? {
|
|
||||||
get { _width }
|
|
||||||
set {
|
|
||||||
if let newValue {
|
|
||||||
switch newValue {
|
|
||||||
case .percentage(let percentage):
|
|
||||||
if percentage <= 100.0 {
|
|
||||||
_width = newValue
|
|
||||||
}
|
|
||||||
case .value(let value):
|
|
||||||
if value > 0 {
|
|
||||||
_width = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_width = nil
|
|
||||||
}
|
|
||||||
updateContainerWidth()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Private Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
private var _width: Width? = nil
|
|
||||||
|
|
||||||
/// To set the widest symbol width from the symbol container in the group.
|
|
||||||
internal var symbolWidth: CGFloat? { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
private lazy var itemStackView = UIStackView().with {
|
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
$0.axis = .horizontal
|
|
||||||
$0.alignment = .leading
|
|
||||||
$0.distribution = .fill
|
|
||||||
$0.spacing = VDSLayout.space1X
|
|
||||||
$0.backgroundColor = .clear
|
|
||||||
}
|
|
||||||
|
|
||||||
internal var symbolLabel = Label().with {
|
|
||||||
$0.isAccessibilityElement = true
|
|
||||||
$0.numberOfLines = 1
|
|
||||||
$0.sizeToFit()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal var textLabel = Label().with {
|
|
||||||
$0.isAccessibilityElement = true
|
|
||||||
$0.lineBreakMode = .byWordWrapping
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Configuration Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
internal var maxWidth: CGFloat { constrainedWidth }
|
|
||||||
internal var minWidth: CGFloat { containerSize.width }
|
|
||||||
internal var containerSize: CGSize { CGSize(width: 45, height: 44) }
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Constraints
|
|
||||||
//--------------------------------------------------
|
|
||||||
internal var symbolWidthConstraint: NSLayoutConstraint?
|
|
||||||
internal var itemWidthConstraint: 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()
|
|
||||||
|
|
||||||
// add footnote item stackview.
|
|
||||||
addSubview(itemStackView)
|
|
||||||
itemStackView.pinToSuperView()
|
|
||||||
|
|
||||||
// width constraints
|
|
||||||
itemWidthConstraint = widthAnchor.constraint(equalToConstant: 0).deactivate()
|
|
||||||
|
|
||||||
// add symbol label, text label to stack.
|
|
||||||
itemStackView.addArrangedSubview(symbolLabel)
|
|
||||||
itemStackView.addArrangedSubview(textLabel)
|
|
||||||
itemStackView.setCustomSpacing(VDSLayout.space1X, after: symbolLabel)
|
|
||||||
|
|
||||||
symbolWidthConstraint = symbolLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0)
|
|
||||||
symbolWidthConstraint?.isActive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setDefaults() {
|
|
||||||
super.setDefaults()
|
|
||||||
hideSymbol = false
|
|
||||||
text = nil
|
|
||||||
tooltipModel = nil
|
|
||||||
width = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resets to default settings.
|
|
||||||
open override func reset() {
|
|
||||||
symbolLabel.reset()
|
|
||||||
textLabel.reset()
|
|
||||||
super.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to make changes to the View based off a change events or from local properties.
|
|
||||||
open override func updateView() {
|
|
||||||
super.updateView()
|
|
||||||
|
|
||||||
// Update symbolLabel
|
|
||||||
symbolLabel.text = symbolType
|
|
||||||
symbolLabel.isHidden = symbolType.isEmpty ? true : hideSymbol
|
|
||||||
symbolLabel.textColor = kind.colorConfiguration.getColor(self)
|
|
||||||
symbolLabel.textStyle = size.textStyle.regular
|
|
||||||
symbolLabel.surface = surface
|
|
||||||
|
|
||||||
//Set width to the symbol label
|
|
||||||
if let symbolWidth, symbolWidth > 0 {
|
|
||||||
// Set the widest symbol width from the symbol container in the group.
|
|
||||||
symbolWidthConstraint?.constant = symbolWidth
|
|
||||||
} else {
|
|
||||||
symbolWidthConstraint?.constant = symbolLabel.intrinsicContentSize.width
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update textLabel
|
|
||||||
textLabel.text = text
|
|
||||||
textLabel.textColor = kind.colorConfiguration.getColor(self)
|
|
||||||
textLabel.textStyle = size.textStyle.regular
|
|
||||||
textLabel.surface = surface
|
|
||||||
|
|
||||||
// Set the textLabel attributes
|
|
||||||
if let tooltipModel {
|
|
||||||
var attributes: [any LabelAttributeModel] = []
|
|
||||||
attributes.append(TooltipLabelAttribute(surface: surface, model: tooltipModel, presenter: self))
|
|
||||||
textLabel.attributes = attributes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update container width after updating content.
|
|
||||||
internal func updateContainerWidth() {
|
|
||||||
var newWidth = 0.0
|
|
||||||
switch width {
|
|
||||||
case .percentage(let percentage):
|
|
||||||
newWidth = max(maxWidth * ((percentage) / 100), minWidth)
|
|
||||||
|
|
||||||
case .value(let value):
|
|
||||||
newWidth = value > maxWidth ? maxWidth : value
|
|
||||||
|
|
||||||
case nil:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
itemWidthConstraint?.deactivate()
|
|
||||||
|
|
||||||
if newWidth > minWidth && newWidth < maxWidth {
|
|
||||||
itemWidthConstraint?.constant = newWidth
|
|
||||||
itemWidthConstraint?.activate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -13,6 +13,7 @@ import Combine
|
|||||||
/// An icon is a graphical element that conveys information at a glance. It helps orient
|
/// An icon is a graphical element that conveys information at a glance. It helps orient
|
||||||
/// a customer, explain functionality and draw attention to interactive elements. Icons
|
/// a customer, explain functionality and draw attention to interactive elements. Icons
|
||||||
/// should have a functional purpose and should never be used for decoration.
|
/// should have a functional purpose and should never be used for decoration.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSIcon)
|
@objc(VDSIcon)
|
||||||
open class Icon: View {
|
open class Icon: View {
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
/// A stepper is a two-segment control that people use to increase or decrease an incremental value.'
|
/// A stepper is a two-segment control that people use to increase or decrease an incremental value.'
|
||||||
|
@objcMembers
|
||||||
@objc(VDSInputStepper)
|
@objc(VDSInputStepper)
|
||||||
open class InputStepper: EntryFieldBase<Int> {
|
open class InputStepper: EntryFieldBase<Int> {
|
||||||
|
|
||||||
@ -330,6 +331,8 @@ open class InputStepper: EntryFieldBase<Int> {
|
|||||||
|
|
||||||
stepperWidthConstraint?.deactivate()
|
stepperWidthConstraint?.deactivate()
|
||||||
widthConstraint?.deactivate()
|
widthConstraint?.deactivate()
|
||||||
|
trailingLessThanEqualsConstraint?.deactivate()
|
||||||
|
trailingEqualsConstraint?.deactivate()
|
||||||
|
|
||||||
var widthConstraintConstant: CGFloat?
|
var widthConstraintConstant: CGFloat?
|
||||||
|
|
||||||
@ -347,6 +350,9 @@ open class InputStepper: EntryFieldBase<Int> {
|
|||||||
if let widthConstraintConstant {
|
if let widthConstraintConstant {
|
||||||
widthConstraint?.constant = widthConstraintConstant
|
widthConstraint?.constant = widthConstraintConstant
|
||||||
widthConstraint?.activate()
|
widthConstraint?.activate()
|
||||||
|
trailingLessThanEqualsConstraint?.activate()
|
||||||
|
} else {
|
||||||
|
trailingEqualsConstraint?.activate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Edge insets if size changes applied.
|
// Update Edge insets if size changes applied.
|
||||||
|
|||||||
@ -39,27 +39,6 @@ public extension String {
|
|||||||
func isValid(range: NSRange) -> Bool {
|
func isValid(range: NSRange) -> Bool {
|
||||||
range.location >= 0 && range.length > 0 && range.location + range.length <= count
|
range.location >= 0 && range.length > 0 && range.location + range.length <= count
|
||||||
}
|
}
|
||||||
|
|
||||||
func index(from: Int) -> Index {
|
|
||||||
return self.index(startIndex, offsetBy: from)
|
|
||||||
}
|
|
||||||
|
|
||||||
func substring(from: Int) -> String {
|
|
||||||
let fromIndex = index(from: from)
|
|
||||||
return String(self[fromIndex...])
|
|
||||||
}
|
|
||||||
|
|
||||||
func substring(to: Int) -> String {
|
|
||||||
let toIndex = index(from: to)
|
|
||||||
return String(self[..<toIndex])
|
|
||||||
}
|
|
||||||
|
|
||||||
func substring(with r: Range<Int>) -> String {
|
|
||||||
let startIndex = index(from: r.lowerBound)
|
|
||||||
let endIndex = index(from: r.upperBound)
|
|
||||||
return String(self[startIndex..<endIndex])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension NSAttributedString {
|
public extension NSAttributedString {
|
||||||
|
|||||||
@ -63,15 +63,18 @@ public struct TextStyleLabelAttribute: LabelAttributeModel {
|
|||||||
|
|
||||||
//set lineHeight
|
//set lineHeight
|
||||||
if textStyle.lineHeight > 0.0 {
|
if textStyle.lineHeight > 0.0 {
|
||||||
let lineHeight = textStyle.lineHeight + abs(textStyle.edgeInsets.bottom) + abs(textStyle.edgeInsets.top)
|
let lineHeight = textStyle.lineHeight
|
||||||
|
let adjustment = lineHeight > textStyle.font.lineHeight ? 2.0 : 1.0
|
||||||
|
let baselineOffset = (lineHeight - textStyle.font.lineHeight) / 2.0 / adjustment
|
||||||
let paragraph = NSMutableParagraphStyle().with {
|
let paragraph = NSMutableParagraphStyle().with {
|
||||||
$0.maximumLineHeight = lineHeight
|
$0.maximumLineHeight = lineHeight
|
||||||
$0.minimumLineHeight = lineHeight
|
$0.minimumLineHeight = lineHeight
|
||||||
$0.alignment = textPosition.value
|
$0.alignment = textPosition.value
|
||||||
$0.lineBreakMode = lineBreakMode
|
$0.lineBreakMode = lineBreakMode
|
||||||
}
|
}
|
||||||
attributedString.removeAttribute(.baselineOffset, range: range)
|
attributedString.removeAttribute(.baselineOffset, range: range)
|
||||||
attributedString.removeAttribute(.paragraphStyle, range: range)
|
attributedString.removeAttribute(.paragraphStyle, range: range)
|
||||||
|
attributedString.addAttribute(.baselineOffset, value: baselineOffset, range: range)
|
||||||
attributedString.addAttribute(.paragraphStyle, value: paragraph, range: range)
|
attributedString.addAttribute(.paragraphStyle, value: paragraph, range: range)
|
||||||
|
|
||||||
} else if textPosition != .left {
|
} else if textPosition != .left {
|
||||||
@ -84,4 +87,3 @@ public struct TextStyleLabelAttribute: LabelAttributeModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import Combine
|
|||||||
|
|
||||||
/// Label is a standard view used to draw text with applying Typography through ``TextStyle`` as well
|
/// Label is a standard view used to draw text with applying Typography through ``TextStyle`` as well
|
||||||
/// as other attributes using any implemetation of ``LabelAttributeModel``.
|
/// as other attributes using any implemetation of ``LabelAttributeModel``.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSLabel)
|
@objc(VDSLabel)
|
||||||
open class Label: UILabel, ViewProtocol, UserInfoable {
|
open class Label: UILabel, ViewProtocol, UserInfoable {
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
/// A line visually separates content sections or elements in lists, tables and layouts to indicate content hierarchy.
|
/// A line visually separates content sections or elements in lists, tables and layouts to indicate content hierarchy.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSLine)
|
@objc(VDSLine)
|
||||||
open class Line: View {
|
open class Line: View {
|
||||||
|
|
||||||
|
|||||||
@ -1,239 +0,0 @@
|
|||||||
//
|
|
||||||
// ListUnordered.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Vasavi Kanamarlapudi on 16/10/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import VDSCoreTokens
|
|
||||||
|
|
||||||
/// List unordered breaks up related content into distinct phrases or sentences, which improves scannability.
|
|
||||||
/// This component should be used when the text items don’t need to be in numeric order.
|
|
||||||
@objcMembers
|
|
||||||
@objc(VDSListUnordered)
|
|
||||||
open class ListUnordered: View {
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// 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: - Enums
|
|
||||||
//--------------------------------------------------
|
|
||||||
/// Enum that represents the size availble for the component.
|
|
||||||
public enum Size: String, DefaultValuing, CaseIterable {
|
|
||||||
case large
|
|
||||||
case medium
|
|
||||||
case small
|
|
||||||
case micro
|
|
||||||
|
|
||||||
public static var defaultValue: Self { .large }
|
|
||||||
|
|
||||||
/// TextStyle relative to Size.
|
|
||||||
public var textStyle: TextStyle.StandardStyle {
|
|
||||||
switch self {
|
|
||||||
case .large:
|
|
||||||
return .bodyLarge
|
|
||||||
case .medium:
|
|
||||||
return .bodyMedium
|
|
||||||
case .small:
|
|
||||||
return .bodySmall
|
|
||||||
case .micro:
|
|
||||||
return .micro
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enum that represents the type of spacing available for the component.
|
|
||||||
public enum Spacing: String, CaseIterable {
|
|
||||||
case standard, compact
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Public Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
/// Size of the component. The default size is Large.
|
|
||||||
open var size: Size = .defaultValue { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
/// Spacing type of the component.
|
|
||||||
open var spacing: Spacing = .standard { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
/// Lead-in text that shows as the top text for the component. This is optional.
|
|
||||||
open var leadInText: String? = nil { didSet { setNeedsUpdate() } }
|
|
||||||
|
|
||||||
/// Array of unordered list items to show for the component.
|
|
||||||
open var unorderedList: [ListUnorderedItemModel] = [] { didSet { setNeedsUpdate() }}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Configuration Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
// It can be used for Glyph level 1.
|
|
||||||
private var disc = "•"
|
|
||||||
|
|
||||||
// It can be used for Glyph Level 2.
|
|
||||||
private var endash = "–"
|
|
||||||
|
|
||||||
// Spacing between the list items.
|
|
||||||
private var spaceBetweenItems: CGFloat {
|
|
||||||
switch (size, spacing) {
|
|
||||||
case (.large, .standard):
|
|
||||||
return VDSLayout.space4X
|
|
||||||
case (.medium, .standard), (.small, .standard), (.micro, .standard):
|
|
||||||
return VDSLayout.space3X
|
|
||||||
case (.large, .compact):
|
|
||||||
return VDSLayout.space2X
|
|
||||||
case (.medium, .compact), (.small, .compact), (.micro, .compact):
|
|
||||||
return VDSLayout.space1X
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Padding that can be used in an item between the glyph and the item text.
|
|
||||||
private var padding: CGFloat {
|
|
||||||
switch (size, spacing) {
|
|
||||||
case (.large, .standard), (.large, .compact):
|
|
||||||
return VDSLayout.space3X
|
|
||||||
case (.medium, .standard), (.small, .standard), (.micro, .standard), (.medium, .compact), (.small, .compact), (.micro, .compact):
|
|
||||||
return VDSLayout.space2X
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark)
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Private Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
private lazy var listStackView = UIStackView().with {
|
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
$0.axis = .vertical
|
|
||||||
$0.distribution = .fill
|
|
||||||
$0.spacing = spaceBetweenItems
|
|
||||||
$0.backgroundColor = .clear
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Overrides
|
|
||||||
//--------------------------------------------------
|
|
||||||
/// Called once when a view is initialized and is used to Setup additional UI or other constants and config.texturations.
|
|
||||||
open override func setup() {
|
|
||||||
super.setup()
|
|
||||||
|
|
||||||
// add stackview
|
|
||||||
addSubview(listStackView)
|
|
||||||
listStackView.heightGreaterThanEqualTo(constant:0)
|
|
||||||
listStackView.pinToSuperView()
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setDefaults() {
|
|
||||||
super.setDefaults()
|
|
||||||
leadInText = nil
|
|
||||||
unorderedList = []
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resets to default settings.
|
|
||||||
open override func reset() {
|
|
||||||
super.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to make changes to the View based off a change events or from local properties.
|
|
||||||
open override func updateView() {
|
|
||||||
super.updateView()
|
|
||||||
listStackView.removeArrangedSubviews()
|
|
||||||
listStackView.subviews.forEach { $0.removeFromSuperview() }
|
|
||||||
listStackView.spacing = spaceBetweenItems
|
|
||||||
|
|
||||||
if leadInText != nil {
|
|
||||||
let listItem = getListItem(with:self.leadInText, surface: surface)
|
|
||||||
listStackView.addArrangedSubview(listItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
unorderedList.forEach { item in
|
|
||||||
let listItem = getListItem(levelOneText: item.levelOneText, surface: surface)
|
|
||||||
listStackView.addArrangedSubview(listItem)
|
|
||||||
|
|
||||||
item.levelTwoText?.forEach { text in
|
|
||||||
let listItem = getListItem(levelTwoText: text, surface: surface)
|
|
||||||
listStackView.addArrangedSubview(listItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Private Methods
|
|
||||||
//--------------------------------------------------
|
|
||||||
// Get Label with the required text and text formats.
|
|
||||||
func getLabel(with text: String?, surface: Surface) -> Label {
|
|
||||||
let textLabel = Label().with {
|
|
||||||
$0.isAccessibilityElement = true
|
|
||||||
$0.lineBreakMode = .byWordWrapping
|
|
||||||
$0.text = text
|
|
||||||
$0.textStyle = size.textStyle.regular
|
|
||||||
$0.textColor = textColorConfiguration.getColor(surface)
|
|
||||||
$0.surface = surface
|
|
||||||
}
|
|
||||||
return textLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the list item with the required text (LeadInText, Level 1 Text, Level 2 Text).
|
|
||||||
func getListItem(with leadInText:String? = nil, levelOneText: String? = nil, levelTwoText: String? = nil, surface:Surface) -> UIView {
|
|
||||||
let itemStackView = UIStackView().with {
|
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
$0.axis = .horizontal
|
|
||||||
$0.alignment = .leading
|
|
||||||
$0.distribution = .fill
|
|
||||||
$0.spacing = padding
|
|
||||||
$0.backgroundColor = .clear
|
|
||||||
}
|
|
||||||
|
|
||||||
// StackView with LeadIntext if provided.
|
|
||||||
if leadInText != nil {
|
|
||||||
let leadTextLabel = getLabel(with: leadInText, surface: surface)
|
|
||||||
itemStackView.addArrangedSubview(leadTextLabel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StackView with Level 1 Text if provided.
|
|
||||||
if levelOneText != nil {
|
|
||||||
|
|
||||||
// Add level 1 glyph: 'disc, bold'
|
|
||||||
let discLabel = getLabel(with: disc, surface: surface)
|
|
||||||
discLabel.widthAnchor.constraint(equalToConstant: discLabel.intrinsicContentSize.width).activate()
|
|
||||||
itemStackView.addArrangedSubview(discLabel)
|
|
||||||
|
|
||||||
// Add level 1 Text
|
|
||||||
let levelOneLabel = getLabel(with: levelOneText, surface: surface)
|
|
||||||
itemStackView.addArrangedSubview(levelOneLabel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StackView with Level 2 Text if provided.
|
|
||||||
if levelTwoText != nil {
|
|
||||||
|
|
||||||
// Set level 2 leading space as needed for alignment.
|
|
||||||
let discSpaceView = View()
|
|
||||||
let discLabel = getLabel(with: disc, surface: surface)
|
|
||||||
discSpaceView.widthAnchor.constraint(equalToConstant: discLabel.intrinsicContentSize.width).activate()
|
|
||||||
itemStackView.addArrangedSubview(discSpaceView)
|
|
||||||
|
|
||||||
// Add level 2 glyph: 'en dash, regular'
|
|
||||||
let endashLabel = getLabel(with: endash, surface: surface)
|
|
||||||
endashLabel.widthAnchor.constraint(equalToConstant: endashLabel.intrinsicContentSize.width).activate()
|
|
||||||
itemStackView.addArrangedSubview(endashLabel)
|
|
||||||
|
|
||||||
// Add level 2 Text
|
|
||||||
let levelTwoLabel = getLabel(with: levelTwoText, surface: surface)
|
|
||||||
itemStackView.addArrangedSubview(levelTwoLabel)
|
|
||||||
}
|
|
||||||
return itemStackView
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
MM/DD/YYYY
|
|
||||||
----------------
|
|
||||||
- Initial Brand 3.0 handoff
|
|
||||||
|
|
||||||
05/2/2022
|
|
||||||
----------------
|
|
||||||
- Added Body Medium to size configuration
|
|
||||||
|
|
||||||
05/5/2022
|
|
||||||
----------------
|
|
||||||
- Added Spacing configuration (Standard, Compact) Web handoff
|
|
||||||
|
|
||||||
08/2/2022
|
|
||||||
----------------
|
|
||||||
- Included a VDS Note about the Spacing prop naming rationale
|
|
||||||
|
|
||||||
08/10/2022
|
|
||||||
----------------
|
|
||||||
- Updated default and inverted prop to light and dark surface.
|
|
||||||
|
|
||||||
12/13/2022
|
|
||||||
----------------
|
|
||||||
- Replaced focus border pixel and style & spacing values with tokens.
|
|
||||||
|
|
||||||
01/10/2023
|
|
||||||
----------------
|
|
||||||
- Removed from Anatomy section: “List item text”
|
|
||||||
- Updated “Glyph level 1” to “List Item Level 1”
|
|
||||||
- Updated “Glyph level 2” to “List Item Level 2”
|
|
||||||
- Updated image markers to reflect changes
|
|
||||||
|
|
||||||
02/02/2023
|
|
||||||
----------------
|
|
||||||
- Reduced left padding for all Level 2 sizes so that the Glyph aligns with the text in Level 1.
|
|
||||||
- Added dashed line on all sizes to indicate Level 2 alignment under Level 1.
|
|
||||||
- Changed “endash” to “endash, regular” under Size section.
|
|
||||||
- Updated all Level 1 and Level 2 glyph widths to “Hug”
|
|
||||||
|
|
||||||
12/26/23
|
|
||||||
----------------
|
|
||||||
- Deleted Decisions log
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
//
|
|
||||||
// ListUnorderedItemModel.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Vasavi Kanamarlapudi on 16/10/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
extension ListUnordered {
|
|
||||||
public struct ListUnorderedItemModel: Equatable {
|
|
||||||
|
|
||||||
/// Item Level 1 that shows text with glyph - disc, bold.
|
|
||||||
public var levelOneText: String
|
|
||||||
|
|
||||||
/// Item Level 2 that shows text (one or many) with glyph - en dash. This is optional.
|
|
||||||
public var levelTwoText: [String?]?
|
|
||||||
|
|
||||||
public init(itemLevelOneText: String, itemLevelTwoTexts: [String?]? = nil) {
|
|
||||||
self.levelOneText = itemLevelOneText
|
|
||||||
self.levelTwoText = itemLevelTwoTexts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -11,6 +11,7 @@ import VDSCoreTokens
|
|||||||
|
|
||||||
|
|
||||||
/// A loader is an indicator that uses animation to show customers that there is an indefinite amount of wait time while a task is ongoing, e.g. a page is loading, a form is being submitted. The component disappears when the task is complete.
|
/// A loader is an indicator that uses animation to show customers that there is an indefinite amount of wait time while a task is ongoing, e.g. a page is loading, a form is being submitted. The component disappears when the task is complete.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSLoader)
|
@objc(VDSLoader)
|
||||||
open class Loader: View {
|
open class Loader: View {
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
/// ViewController to show the Loader, this will be presented using the LoaderLaunchable Protocl.
|
/// ViewController to show the Loader, this will be presented using the LoaderLaunchable Protocl.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSLoaderViewController)
|
@objc(VDSLoaderViewController)
|
||||||
open class LoaderViewController: UIViewController, Surfaceable {
|
open class LoaderViewController: UIViewController, Surfaceable {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -1,149 +0,0 @@
|
|||||||
//
|
|
||||||
// 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.
|
|
||||||
@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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
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
|
|
||||||
@ -1,237 +0,0 @@
|
|||||||
//
|
|
||||||
// ModalDialog.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Kanamarlapudi, Vasavi on 09/09/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import VDSCoreTokens
|
|
||||||
|
|
||||||
@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 {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
//
|
|
||||||
// ModalDialogViewController.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Kanamarlapudi, Vasavi on 09/09/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import Combine
|
|
||||||
import VDSCoreTokens
|
|
||||||
|
|
||||||
@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)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
//
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -14,6 +14,7 @@ import Combine
|
|||||||
/// in context. There are four types: information, success, warning and error; each
|
/// in context. There are four types: information, success, warning and error; each
|
||||||
/// with different color and content. They may be screen-specific, flow-specific or
|
/// with different color and content. They may be screen-specific, flow-specific or
|
||||||
/// experience-wide.
|
/// experience-wide.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSNotification)
|
@objc(VDSNotification)
|
||||||
open class Notification: View, ParentViewProtocol {
|
open class Notification: View, ParentViewProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -11,14 +11,13 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
///Pagination is a control that enables customers to navigate multiple pages of content by selecting either a specific page or the next or previous set of four pages.
|
///Pagination is a control that enables customers to navigate multiple pages of content by selecting either a specific page or the next or previous set of four pages.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSPagination)
|
@objc(VDSPagination)
|
||||||
open class Pagination: View {
|
open class Pagination: View {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
private let pageChangedSubject = PassthroughSubject<Pagination, Never>()
|
|
||||||
|
|
||||||
///Maximum component width
|
///Maximum component width
|
||||||
private let maxWidth: CGFloat = 288.0
|
private let maxWidth: CGFloat = 288.0
|
||||||
///Collectionview width anchor
|
///Collectionview width anchor
|
||||||
@ -53,8 +52,6 @@ open class Pagination: View {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Public Properties
|
// MARK: - Public Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
public var pageChangedPublisher: AnyPublisher<Pagination, Never> { pageChangedSubject.eraseToAnyPublisher() }
|
|
||||||
|
|
||||||
///Previous button to select previous page
|
///Previous button to select previous page
|
||||||
public let previousButton: PaginationButton = .init(type: .previous)
|
public let previousButton: PaginationButton = .init(type: .previous)
|
||||||
///Next button to select next page
|
///Next button to select next page
|
||||||
@ -148,11 +145,6 @@ open class Pagination: View {
|
|||||||
.sink { [weak self] value in
|
.sink { [weak self] value in
|
||||||
self?.collectionViewWidthAnchor?.constant = value //As cell width is dynamic i.e cell may contain 2 or 3 or 4 charcters. Make sure that all the visible cells are displayed.
|
self?.collectionViewWidthAnchor?.constant = value //As cell width is dynamic i.e cell may contain 2 or 3 or 4 charcters. Make sure that all the visible cells are displayed.
|
||||||
}.store(in: &subscribers)
|
}.store(in: &subscribers)
|
||||||
|
|
||||||
pageChangedPublisher.sink { [weak self] control in
|
|
||||||
guard let self else { return }
|
|
||||||
onPageDidSelect?(control.selectedPage)
|
|
||||||
}.store(in: &subscribers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func setDefaults() {
|
open override func setDefaults() {
|
||||||
@ -203,7 +195,6 @@ open class Pagination: View {
|
|||||||
let isNextAction = sender == nextButton
|
let isNextAction = sender == nextButton
|
||||||
_selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 }
|
_selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 }
|
||||||
updateSelection()
|
updateSelection()
|
||||||
pageChangedSubject.send(self)
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
UIAccessibility.post(notification: .announcement, argument: paginationDescription)
|
UIAccessibility.post(notification: .announcement, argument: paginationDescription)
|
||||||
@ -258,7 +249,7 @@ extension Pagination: UICollectionViewDelegate, UICollectionViewDataSource, UICo
|
|||||||
guard _selectedPageIndex != indexPath.row else { return }
|
guard _selectedPageIndex != indexPath.row else { return }
|
||||||
_selectedPageIndex = indexPath.row
|
_selectedPageIndex = indexPath.row
|
||||||
updateSelection()
|
updateSelection()
|
||||||
pageChangedSubject.send(self)
|
onPageDidSelect?(selectedPage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import UIKit
|
|||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
///This is customised button for Pagination view
|
///This is customised button for Pagination view
|
||||||
|
@objcMembers
|
||||||
@objc(PaginationButton)
|
@objc(PaginationButton)
|
||||||
open class PaginationButton: ButtonBase {
|
open class PaginationButton: ButtonBase {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSPriceLockup)
|
@objc(VDSPriceLockup)
|
||||||
open class PriceLockup: View, ParentViewProtocol {
|
open class PriceLockup: View, ParentViewProtocol {
|
||||||
|
|
||||||
@ -139,7 +140,6 @@ open class PriceLockup: View, ParentViewProtocol {
|
|||||||
internal var delimiterIndex = 0
|
internal var delimiterIndex = 0
|
||||||
internal var strikethroughLocation = 0
|
internal var strikethroughLocation = 0
|
||||||
internal var strikethroughLength = 0
|
internal var strikethroughLength = 0
|
||||||
internal var strikethroughAccessibilityText: String = "price not offering anymore"
|
|
||||||
|
|
||||||
internal var textPosition:TextPosition = .preDelimiter
|
internal var textPosition:TextPosition = .preDelimiter
|
||||||
enum TextPosition: String, CaseIterable {
|
enum TextPosition: String, CaseIterable {
|
||||||
@ -217,24 +217,6 @@ open class PriceLockup: View, ParentViewProtocol {
|
|||||||
|
|
||||||
open override func setDefaults() {
|
open override func setDefaults() {
|
||||||
super.setDefaults()
|
super.setDefaults()
|
||||||
|
|
||||||
priceLockupLabel.bridge_accessibilityLabelBlock = { [weak self] in
|
|
||||||
guard let self else { return "" }
|
|
||||||
var accessibilityLabels = [String]()
|
|
||||||
if let text = priceLockupLabel.text, !text.isEmpty {
|
|
||||||
if strikethrough, strikethroughLength > 0 {
|
|
||||||
let preText = text.substring(to: strikethroughLocation)
|
|
||||||
let postText = text.substring(from: strikethroughLocation)
|
|
||||||
accessibilityLabels.append(preText)
|
|
||||||
accessibilityLabels.append(strikethroughAccessibilityText)
|
|
||||||
accessibilityLabels.append(postText)
|
|
||||||
} else {
|
|
||||||
accessibilityLabels.append(text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return accessibilityLabels.joined(separator: " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
bold = false
|
bold = false
|
||||||
hideCurrency = false
|
hideCurrency = false
|
||||||
leadingText = nil
|
leadingText = nil
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import UIKit
|
|||||||
/// Radio boxes are single-select components through which a customer indicates a choice.
|
/// Radio boxes are single-select components through which a customer indicates a choice.
|
||||||
/// They're stylized ``RadioButtons`` that must always be paired with one or more ``RadioBoxItem``
|
/// They're stylized ``RadioButtons`` that must always be paired with one or more ``RadioBoxItem``
|
||||||
/// in a radio box group. Use radio boxes to display choices like device storage.
|
/// in a radio box group. Use radio boxes to display choices like device storage.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSRadioBoxGroup)
|
@objc(VDSRadioBoxGroup)
|
||||||
open class RadioBoxGroup: SelectorGroupBase<RadioBoxItem>, SelectorGroupSingleSelect {
|
open class RadioBoxGroup: SelectorGroupBase<RadioBoxItem>, SelectorGroupSingleSelect {
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import VDSCoreTokens
|
|||||||
|
|
||||||
/// Radio boxes are single-select components through which a customer indicates a choice
|
/// Radio boxes are single-select components through which a customer indicates a choice
|
||||||
/// that are used within a ``RadioBoxGroup``.
|
/// that are used within a ``RadioBoxGroup``.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSRadioBoxItem)
|
@objc(VDSRadioBoxItem)
|
||||||
open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable, ParentViewProtocol {
|
open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable, ParentViewProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import VDSCoreTokens
|
|||||||
/// Radio buttons are single-select components through which a customer indicates a choice.
|
/// Radio buttons are single-select components through which a customer indicates a choice.
|
||||||
/// They must always be paired with one or more ``RadioButtonItem`` within a ``RadioButtonGroup``.
|
/// They must always be paired with one or more ``RadioButtonItem`` within a ``RadioButtonGroup``.
|
||||||
/// Use radio buttons to display choices like delivery method.
|
/// Use radio buttons to display choices like delivery method.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSRadioButton)
|
@objc(VDSRadioButton)
|
||||||
open class RadioButton: SelectorBase {
|
open class RadioButton: SelectorBase {
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import UIKit
|
|||||||
/// Radio buttons items are single-select components through which a customer indicates a choice.
|
/// Radio buttons items are single-select components through which a customer indicates a choice.
|
||||||
/// They must always be paired with one or more other ``RadioButtonItem`` within a radio button group.
|
/// They must always be paired with one or more other ``RadioButtonItem`` within a radio button group.
|
||||||
/// Use radio buttons to display choices like delivery method.
|
/// Use radio buttons to display choices like delivery method.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSRadioButtonGroup)
|
@objc(VDSRadioButtonGroup)
|
||||||
open class RadioButtonGroup: SelectorGroupBase<RadioButtonItem>, SelectorGroupSingleSelect {
|
open class RadioButtonGroup: SelectorGroupBase<RadioButtonItem>, SelectorGroupSingleSelect {
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import UIKit
|
|||||||
/// Radio buttons items are single-select components through which a customer indicates a choice.
|
/// Radio buttons items are single-select components through which a customer indicates a choice.
|
||||||
/// They must always be paired with one or more other radio button items within a ``RadioButtonGroup``.
|
/// They must always be paired with one or more other radio button items within a ``RadioButtonGroup``.
|
||||||
/// Use radio buttons to display choices like delivery method.
|
/// Use radio buttons to display choices like delivery method.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSRadioButtonItem)
|
@objc(VDSRadioButtonItem)
|
||||||
open class RadioButtonItem: SelectorItemBase<RadioButton> {
|
open class RadioButtonItem: SelectorItemBase<RadioButton> {
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
///Table is view composed of rows and columns, which takes any view into each cell and resizes based on the highest cell height.
|
///Table is view composed of rows and columns, which takes any view into each cell and resizes based on the highest cell height.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTable)
|
@objc(VDSTable)
|
||||||
open class Table: View {
|
open class Table: View {
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ open class Table: View {
|
|||||||
$0.allowsSelection = false
|
$0.allowsSelection = false
|
||||||
$0.showsVerticalScrollIndicator = false
|
$0.showsVerticalScrollIndicator = false
|
||||||
$0.showsHorizontalScrollIndicator = false
|
$0.showsHorizontalScrollIndicator = false
|
||||||
|
$0.isAccessibilityElement = true
|
||||||
$0.backgroundColor = .clear
|
$0.backgroundColor = .clear
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +148,6 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl
|
|||||||
var edgePadding = UIEdgeInsets(top: padding.verticalValue(), left: 0, bottom: padding.verticalValue(), right: padding.horizontalValue())
|
var edgePadding = UIEdgeInsets(top: padding.verticalValue(), left: 0, bottom: padding.verticalValue(), right: padding.horizontalValue())
|
||||||
edgePadding.left = (indexPath.row == 0 && !striped) ? VDSLayout.space1X : padding.horizontalValue()
|
edgePadding.left = (indexPath.row == 0 && !striped) ? VDSLayout.space1X : padding.horizontalValue()
|
||||||
cell.updateCell(content: currentItem, surface: surface, striped: shouldStrip, padding: edgePadding, isHeader: isHeader)
|
cell.updateCell(content: currentItem, surface: surface, striped: shouldStrip, padding: edgePadding, isHeader: isHeader)
|
||||||
setAccessibilityForCell(cell: cell, content: currentItem, path: indexPath)
|
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,38 +162,4 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl
|
|||||||
func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat {
|
func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat {
|
||||||
return columnWidths?[indexPath.row] ?? 0.0
|
return columnWidths?[indexPath.row] ?? 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Accessibility
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
/// To set the accessibility label for the each cell based on the criteria. Table name along with total no of column & row information should be passed in the first cell's accessibility label.
|
|
||||||
private func setAccessibilityForCell(cell: TableCellItem, content: TableItemModel, path: IndexPath) {
|
|
||||||
|
|
||||||
var accLabel = content.component?.accessibilityLabel ?? "Empty"
|
|
||||||
|
|
||||||
///Set the type of header label
|
|
||||||
if path.section == 0 {
|
|
||||||
accLabel.append(", Column Header")
|
|
||||||
} else if path.row == 0 {
|
|
||||||
///As per design team, inspite of column 0 may not look like a header, it should be read as header.
|
|
||||||
accLabel.append(", Row Header")
|
|
||||||
}
|
|
||||||
|
|
||||||
///Set the Row/Column number for each cell
|
|
||||||
if path.row == 0 {
|
|
||||||
accLabel.append(", Row \(path.section + 1), Column \(path.row + 1)")
|
|
||||||
} else {
|
|
||||||
accLabel.append(", Column \(path.row + 1)")
|
|
||||||
}
|
|
||||||
|
|
||||||
///Set the Row header accessibilityLabel at the end of the non-header cells accessibilityLabel
|
|
||||||
if path.section != 0,
|
|
||||||
path.row != 0,
|
|
||||||
let columnHeaderAccLabel = tableHeader.first?.columns[path.row].component?.accessibilityLabel {
|
|
||||||
accLabel.append(", \(columnHeaderAccLabel)")
|
|
||||||
}
|
|
||||||
|
|
||||||
cell.accessibilityLabel = accLabel
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,6 @@ final class TableCellItem: UICollectionViewCell {
|
|||||||
|
|
||||||
private func setupCell() {
|
private func setupCell() {
|
||||||
contentView.backgroundColor = .clear
|
contentView.backgroundColor = .clear
|
||||||
isAccessibilityElement = true
|
|
||||||
|
|
||||||
addSubview(containerView)
|
addSubview(containerView)
|
||||||
containerView.pinToSuperView()
|
containerView.pinToSuperView()
|
||||||
|
|||||||
@ -11,7 +11,8 @@ import VDSCoreTokens
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
extension Tabs {
|
extension Tabs {
|
||||||
@objc(VDSTab)
|
@objcMembers
|
||||||
|
@objc(VDSTab)
|
||||||
open class Tab: Control, Groupable {
|
open class Tab: Control, Groupable {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
/// Tabs are organizational components that group content and allow customers to navigate its display. Use them to separate content when the content is related but doesn’t need to be compared.
|
/// Tabs are organizational components that group content and allow customers to navigate its display. Use them to separate content when the content is related but doesn’t need to be compared.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTabs)
|
@objc(VDSTabs)
|
||||||
open class Tabs: View, ParentViewProtocol {
|
open class Tabs: View, ParentViewProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTabsContainer)
|
@objc(VDSTabsContainer)
|
||||||
open class TabsContainer: View {
|
open class TabsContainer: View {
|
||||||
|
|
||||||
|
|||||||
@ -105,12 +105,14 @@ open class EntryFieldBase<ValueType>: Control, Changeable, FormFieldInternalVali
|
|||||||
// MARK: - Constraints
|
// MARK: - Constraints
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
internal var widthConstraint: NSLayoutConstraint?
|
internal var widthConstraint: NSLayoutConstraint?
|
||||||
|
internal var trailingEqualsConstraint: NSLayoutConstraint?
|
||||||
|
internal var trailingLessThanEqualsConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Configuration Properties
|
// MARK: - Configuration Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// Sizes are from InVision design specs.
|
// Sizes are from InVision design specs.
|
||||||
internal var maxWidth: CGFloat { constrainedWidth }
|
internal var maxWidth: CGFloat { frame.size.width }
|
||||||
internal var minWidth: CGFloat { containerSize.width }
|
internal var minWidth: CGFloat { containerSize.width }
|
||||||
internal var containerSize: CGSize { CGSize(width: minWidth, height: 44) }
|
internal var containerSize: CGSize { CGSize(width: minWidth, height: 44) }
|
||||||
|
|
||||||
@ -256,9 +258,15 @@ open class EntryFieldBase<ValueType>: Control, Changeable, FormFieldInternalVali
|
|||||||
|
|
||||||
let layoutGuide = UILayoutGuide()
|
let layoutGuide = UILayoutGuide()
|
||||||
addLayoutGuide(layoutGuide)
|
addLayoutGuide(layoutGuide)
|
||||||
layoutGuide.pinToSuperView()
|
layoutGuide
|
||||||
|
.pinTop()
|
||||||
|
.pinLeading()
|
||||||
|
.pinBottom()
|
||||||
|
|
||||||
|
trailingEqualsConstraint = layoutGuide.pinTrailing(anchor: trailingAnchor)
|
||||||
|
|
||||||
// width constraints
|
// width constraints
|
||||||
|
trailingLessThanEqualsConstraint = layoutGuide.pinTrailingLessThanOrEqualTo(anchor: trailingAnchor)?.deactivate()
|
||||||
widthConstraint = layoutGuide.widthAnchor.constraint(equalToConstant: 0).deactivate()
|
widthConstraint = layoutGuide.widthAnchor.constraint(equalToConstant: 0).deactivate()
|
||||||
|
|
||||||
// Add mainStackView to the view
|
// Add mainStackView to the view
|
||||||
@ -544,10 +552,15 @@ open class EntryFieldBase<ValueType>: Control, Changeable, FormFieldInternalVali
|
|||||||
|
|
||||||
internal func updateContainerWidth() {
|
internal func updateContainerWidth() {
|
||||||
widthConstraint?.deactivate()
|
widthConstraint?.deactivate()
|
||||||
|
trailingLessThanEqualsConstraint?.deactivate()
|
||||||
|
trailingEqualsConstraint?.deactivate()
|
||||||
|
|
||||||
if let width, width >= minWidth, width <= maxWidth {
|
if let width, width >= minWidth, width <= maxWidth {
|
||||||
widthConstraint?.constant = width
|
widthConstraint?.constant = width
|
||||||
widthConstraint?.activate()
|
widthConstraint?.activate()
|
||||||
|
trailingLessThanEqualsConstraint?.activate()
|
||||||
|
} else {
|
||||||
|
trailingEqualsConstraint?.activate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import Combine
|
|||||||
/// An input field is an input wherein a customer enters information. They typically appear in forms.
|
/// An input field is an input wherein a customer enters information. They typically appear in forms.
|
||||||
/// Specialized input fields capture credit card numbers, inline actions, passwords, phone numbers,
|
/// Specialized input fields capture credit card numbers, inline actions, passwords, phone numbers,
|
||||||
/// dates and security codes in their correct formats.
|
/// dates and security codes in their correct formats.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSInputField)
|
@objc(VDSInputField)
|
||||||
open class InputField: EntryFieldBase<String> {
|
open class InputField: EntryFieldBase<String> {
|
||||||
|
|
||||||
@ -46,9 +47,8 @@ open class InputField: EntryFieldBase<String> {
|
|||||||
|
|
||||||
internal override var minWidth: CGFloat { fieldType.handler().minWidth }
|
internal override var minWidth: CGFloat { fieldType.handler().minWidth }
|
||||||
internal override var maxWidth: CGFloat {
|
internal override var maxWidth: CGFloat {
|
||||||
let frameWidth = constrainedWidth
|
let frameWidth = frame.size.width
|
||||||
let halfWidth = (frameWidth - horizontalStackView.spacing) / 2
|
return helperTextPlacement == .right ? (frameWidth - horizontalStackView.spacing) / 2 : frameWidth
|
||||||
return helperTextPlacement == .right && halfWidth > minWidth * 2 ? halfWidth : frameWidth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The is used for the for adding the helperLabel to the right of the containerView.
|
/// The is used for the for adding the helperLabel to the right of the containerView.
|
||||||
@ -320,12 +320,15 @@ open class InputField: EntryFieldBase<String> {
|
|||||||
|
|
||||||
internal override func updateContainerWidth() {
|
internal override func updateContainerWidth() {
|
||||||
widthConstraint?.deactivate()
|
widthConstraint?.deactivate()
|
||||||
|
trailingLessThanEqualsConstraint?.deactivate()
|
||||||
|
trailingEqualsConstraint?.deactivate()
|
||||||
|
|
||||||
//see if there is a widthPercentage and follow the same pattern as done for "width"
|
//see if there is a widthPercentage and follow the same pattern as done for "width"
|
||||||
let currentWidth = (horizontalPinnedWidth() ?? 0) * (widthPercentage ?? 0)
|
let currentWidth = (horizontalPinnedWidth() ?? 0) * (widthPercentage ?? 0)
|
||||||
if currentWidth >= minWidth, currentWidth <= maxWidth {
|
if currentWidth >= minWidth, currentWidth <= maxWidth {
|
||||||
widthConstraint?.constant = currentWidth
|
widthConstraint?.constant = currentWidth
|
||||||
widthConstraint?.activate()
|
widthConstraint?.activate()
|
||||||
|
trailingLessThanEqualsConstraint?.activate()
|
||||||
} else {
|
} else {
|
||||||
super.updateContainerWidth()
|
super.updateContainerWidth()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import Combine
|
import Combine
|
||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTextField)
|
@objc(VDSTextField)
|
||||||
open class TextField: UITextField, ViewProtocol, Errorable {
|
open class TextField: UITextField, ViewProtocol, Errorable {
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import Combine
|
|||||||
|
|
||||||
/// A text area is an input wherein a customer enters long-form information.
|
/// A text area is an input wherein a customer enters long-form information.
|
||||||
/// Use a text area when you want customers to enter text that’s longer than a single line.
|
/// Use a text area when you want customers to enter text that’s longer than a single line.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTextArea)
|
@objc(VDSTextArea)
|
||||||
open class TextArea: EntryFieldBase<String> {
|
open class TextArea: EntryFieldBase<String> {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import Combine
|
import Combine
|
||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTextView)
|
@objc(VDSTextView)
|
||||||
open class TextView: UITextView, ViewProtocol, Errorable {
|
open class TextView: UITextView, ViewProtocol, Errorable {
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import VDSCoreTokens
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTileContainer)
|
@objc(VDSTileContainer)
|
||||||
open class TileContainer: TileContainerBase<TileContainer.Padding> {
|
open class TileContainer: TileContainerBase<TileContainer.Padding> {
|
||||||
|
|
||||||
@ -345,15 +346,8 @@ open class TileContainerBase<PaddingType: DefaultValuing & Valuing>: View where
|
|||||||
containerView.setAccessibilityLabel(for: views)
|
containerView.setAccessibilityLabel(for: views)
|
||||||
|
|
||||||
//append all children that are accessible
|
//append all children that are accessible
|
||||||
if containerView.isAccessibilityElement {
|
items.append(contentsOf: elements)
|
||||||
elements.forEach({ element in
|
|
||||||
if element.accessibilityTraits.contains(.button) || element.accessibilityTraits.contains(.link) {
|
|
||||||
items.append(element)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
items.append(contentsOf: elements)
|
|
||||||
}
|
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
set {}
|
set {}
|
||||||
@ -453,6 +447,33 @@ open class TileContainerBase<PaddingType: DefaultValuing & Valuing>: View where
|
|||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
//Overriding Nil Width Rules
|
//Overriding Nil Width Rules
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
//Rule 1:
|
||||||
|
//In the scenario where we only have a height but the multiplie is nil, we
|
||||||
|
//want to set the width with the parent's width which will more or less "fill"
|
||||||
|
//the container horizontally
|
||||||
|
//- height is set
|
||||||
|
//- width is not set
|
||||||
|
//- aspectRatio is not set
|
||||||
|
if let superviewWidth, superviewWidth > 0,
|
||||||
|
containerViewHeight != nil,
|
||||||
|
containerViewWidth == nil,
|
||||||
|
multiplier == nil {
|
||||||
|
containerViewWidth = superviewWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
//Rule 2:
|
||||||
|
//In the scenario where no width and height is set, want to set the width with the
|
||||||
|
//parent's width which will more or less "fill" the container horizontally
|
||||||
|
//- height is not set
|
||||||
|
//- width is not set
|
||||||
|
else if let superviewWidth, superviewWidth > 0,
|
||||||
|
containerViewWidth == nil,
|
||||||
|
containerViewHeight == nil {
|
||||||
|
containerViewWidth = superviewWidth
|
||||||
|
}
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
//Width + AspectRatio Constraint
|
//Width + AspectRatio Constraint
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
@ -478,14 +499,6 @@ open class TileContainerBase<PaddingType: DefaultValuing & Valuing>: View where
|
|||||||
aspectRatioConstraint = widthAnchor.constraint(equalTo: heightAnchor, multiplier: multiplier)
|
aspectRatioConstraint = widthAnchor.constraint(equalTo: heightAnchor, multiplier: multiplier)
|
||||||
aspectRatioConstraint?.activate()
|
aspectRatioConstraint?.activate()
|
||||||
|
|
||||||
}
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
//Multiplier, meaning it was pinned with width only Constraint
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
else if let multiplier {
|
|
||||||
aspectRatioConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: multiplier)
|
|
||||||
aspectRatioConstraint?.activate()
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
@ -507,6 +520,12 @@ open class TileContainerBase<PaddingType: DefaultValuing & Valuing>: View where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is the size of the superview's allowed space for this container first by constrained size which would include padding/inset values an
|
||||||
|
private var superviewWidth: CGFloat? {
|
||||||
|
horizontalPinnedWidth() ?? superview?.frame.size.width
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TileContainerBase {
|
extension TileContainerBase {
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import Combine
|
|||||||
/// support quick scanning and engagement. A Tilelet is fully clickable and
|
/// support quick scanning and engagement. A Tilelet is fully clickable and
|
||||||
/// while it can include an arrow CTA, it does not require one in order to
|
/// while it can include an arrow CTA, it does not require one in order to
|
||||||
/// function.
|
/// function.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTilelet)
|
@objc(VDSTilelet)
|
||||||
open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
||||||
|
|
||||||
@ -28,9 +29,9 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
|||||||
public var value: CGFloat {
|
public var value: CGFloat {
|
||||||
switch self {
|
switch self {
|
||||||
case .small:
|
case .small:
|
||||||
return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space3X
|
return UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space4X
|
||||||
case .large:
|
case .large:
|
||||||
return UIDevice.isIPad ? VDSLayout.space6X : VDSLayout.space4X
|
return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space6X
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var backgroundColorSurface: Surface {
|
private var backgroundColorSurface: Surface {
|
||||||
backgroundColorConfiguration.getColor(self).isDark() ? .dark : .light
|
backgroundColorConfiguration.getColor(self).surface
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -279,7 +280,6 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Constraints
|
// MARK: - Constraints
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
internal var iconContainerHeightConstraint: NSLayoutConstraint?
|
|
||||||
internal var titleLockupWidthConstraint: NSLayoutConstraint?
|
internal var titleLockupWidthConstraint: NSLayoutConstraint?
|
||||||
internal var titleLockupTrailingConstraint: NSLayoutConstraint?
|
internal var titleLockupTrailingConstraint: NSLayoutConstraint?
|
||||||
internal var titleLockupTopConstraint: NSLayoutConstraint?
|
internal var titleLockupTopConstraint: NSLayoutConstraint?
|
||||||
@ -328,15 +328,15 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
|||||||
|
|
||||||
iconContainerView.addSubview(descriptiveIcon)
|
iconContainerView.addSubview(descriptiveIcon)
|
||||||
iconContainerView.addSubview(directionalIcon)
|
iconContainerView.addSubview(directionalIcon)
|
||||||
iconContainerHeightConstraint = iconContainerView.height(constant: 0)
|
|
||||||
descriptiveIcon
|
descriptiveIcon
|
||||||
.pinLeading()
|
.pinLeading()
|
||||||
.pinTopGreaterThanOrEqualTo()
|
.pinTop()
|
||||||
.pinBottom()
|
.pinBottom()
|
||||||
|
|
||||||
directionalIcon
|
directionalIcon
|
||||||
.pinTrailing()
|
.pinTrailing()
|
||||||
.pinTopGreaterThanOrEqualTo()
|
.pinTop()
|
||||||
.pinBottom()
|
.pinBottom()
|
||||||
|
|
||||||
badge.bottomAnchor.constraint(equalTo: badge.label.bottomAnchor, constant: 2).activate()
|
badge.bottomAnchor.constraint(equalTo: badge.label.bottomAnchor, constant: 2).activate()
|
||||||
@ -468,7 +468,6 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
|||||||
private func updateBadge() {
|
private func updateBadge() {
|
||||||
if let badgeModel {
|
if let badgeModel {
|
||||||
badge.text = badgeModel.text
|
badge.text = badgeModel.text
|
||||||
badge.textColor = badgeModel.textColor
|
|
||||||
badge.fillColor = badgeModel.fillColor
|
badge.fillColor = badgeModel.fillColor
|
||||||
badge.numberOfLines = badgeModel.numberOfLines
|
badge.numberOfLines = badgeModel.numberOfLines
|
||||||
badge.surface = backgroundColorSurface
|
badge.surface = backgroundColorSurface
|
||||||
@ -559,7 +558,6 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
|||||||
descriptiveIcon.color = color
|
descriptiveIcon.color = color
|
||||||
}
|
}
|
||||||
descriptiveIcon.size = descriptiveIconModel.size
|
descriptiveIcon.size = descriptiveIconModel.size
|
||||||
iconContainerHeightConstraint?.constant = descriptiveIcon.size.dimensions.height
|
|
||||||
descriptiveIcon.surface = backgroundColorSurface
|
descriptiveIcon.surface = backgroundColorSurface
|
||||||
showIconContainerView = true
|
showIconContainerView = true
|
||||||
}
|
}
|
||||||
@ -570,7 +568,6 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
|||||||
directionalIcon.color = color
|
directionalIcon.color = color
|
||||||
}
|
}
|
||||||
directionalIcon.size = directionalIconModel.size.value
|
directionalIcon.size = directionalIconModel.size.value
|
||||||
iconContainerHeightConstraint?.constant = directionalIcon.size.dimensions.height
|
|
||||||
directionalIcon.surface = backgroundColorSurface
|
directionalIcon.surface = backgroundColorSurface
|
||||||
showIconContainerView = true
|
showIconContainerView = true
|
||||||
}
|
}
|
||||||
@ -601,7 +598,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateTextPositionAlignment() {
|
private func updateTextPositionAlignment() {
|
||||||
guard aspectRatio != .none || height != nil else { return }
|
guard width != nil && (aspectRatio != .none || height != nil) else { return }
|
||||||
switch textPostion {
|
switch textPostion {
|
||||||
case .top:
|
case .top:
|
||||||
titleLockupTopConstraint?.activate()
|
titleLockupTopConstraint?.activate()
|
||||||
|
|||||||
@ -15,9 +15,6 @@ extension Tilelet {
|
|||||||
/// Text that will be used for the badge.
|
/// Text that will be used for the badge.
|
||||||
public var text: String = ""
|
public var text: String = ""
|
||||||
|
|
||||||
/// Text color that will be used for the badge.
|
|
||||||
public var textColor: Badge.TextColor?
|
|
||||||
|
|
||||||
/// Fill color that will be used for the badge.
|
/// Fill color that will be used for the badge.
|
||||||
public var fillColor: Badge.FillColor
|
public var fillColor: Badge.FillColor
|
||||||
|
|
||||||
@ -33,9 +30,8 @@ extension Tilelet {
|
|||||||
/// LineBreakMode used in Badge label.
|
/// LineBreakMode used in Badge label.
|
||||||
public var lineBreakMode: NSLineBreakMode
|
public var lineBreakMode: NSLineBreakMode
|
||||||
|
|
||||||
public init(text: String, textColor: Badge.TextColor? = nil, fillColor: Badge.FillColor = .red, surface: Surface = .light, numberOfLines: Int = 0, maxWidth: CGFloat? = nil, lineBreakMode: NSLineBreakMode = .byTruncatingTail) {
|
public init(text: String, fillColor: Badge.FillColor = .red, surface: Surface = .light, numberOfLines: Int = 0, maxWidth: CGFloat? = nil, lineBreakMode: NSLineBreakMode = .byTruncatingTail) {
|
||||||
self.text = text
|
self.text = text
|
||||||
self.textColor = textColor
|
|
||||||
self.fillColor = fillColor
|
self.fillColor = fillColor
|
||||||
self.surface = surface
|
self.surface = surface
|
||||||
self.numberOfLines = numberOfLines
|
self.numberOfLines = numberOfLines
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import Combine
|
|||||||
|
|
||||||
/// Title Lockup ensures the readability of words on the screen
|
/// Title Lockup ensures the readability of words on the screen
|
||||||
/// with approved built in text size configurations.
|
/// with approved built in text size configurations.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTitleLockup)
|
@objc(VDSTitleLockup)
|
||||||
open class TitleLockup: View, ParentViewProtocol {
|
open class TitleLockup: View, ParentViewProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import Combine
|
|||||||
|
|
||||||
/// A toggle is a control that lets customers instantly turn on
|
/// A toggle is a control that lets customers instantly turn on
|
||||||
/// or turn off a single option, setting or function.
|
/// or turn off a single option, setting or function.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSToggle)
|
@objc(VDSToggle)
|
||||||
open class Toggle: Control, Changeable, FormFieldable, ParentViewProtocol {
|
open class Toggle: Control, Changeable, FormFieldable, ParentViewProtocol {
|
||||||
|
|
||||||
@ -207,8 +208,8 @@ open class Toggle: Control, Changeable, FormFieldable, ParentViewProtocol {
|
|||||||
|
|
||||||
//toggle
|
//toggle
|
||||||
toggleConstraints = [
|
toggleConstraints = [
|
||||||
toggleView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
toggleView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor),
|
||||||
toggleView.trailingAnchor.constraint(equalTo: trailingAnchor)
|
toggleView.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor)
|
||||||
]
|
]
|
||||||
|
|
||||||
//toggle and label variants
|
//toggle and label variants
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import Combine
|
|||||||
|
|
||||||
/// A toggle is a control that lets customers instantly turn on
|
/// A toggle is a control that lets customers instantly turn on
|
||||||
/// or turn off a single option, setting or function.
|
/// or turn off a single option, setting or function.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSToggleView)
|
@objc(VDSToggleView)
|
||||||
open class ToggleView: Control, Changeable, FormFieldable {
|
open class ToggleView: Control, Changeable, FormFieldable {
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import Combine
|
|||||||
/// A tooltip is an overlay that clarifies another component or content
|
/// A tooltip is an overlay that clarifies another component or content
|
||||||
/// element. It is triggered when a customer hovers, clicks or taps
|
/// element. It is triggered when a customer hovers, clicks or taps
|
||||||
/// the tooltip icon.
|
/// the tooltip icon.
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTooltip)
|
@objc(VDSTooltip)
|
||||||
open class Tooltip: Control, TooltipLaunchable {
|
open class Tooltip: Control, TooltipLaunchable {
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import UIKit
|
|||||||
import Combine
|
import Combine
|
||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTooltipAlertViewController)
|
@objc(VDSTooltipAlertViewController)
|
||||||
open class TooltipAlertViewController: UIViewController, Surfaceable {
|
open class TooltipAlertViewController: UIViewController, Surfaceable {
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import VDSCoreTokens
|
import VDSCoreTokens
|
||||||
|
|
||||||
|
@objcMembers
|
||||||
@objc(VDSTooltipDialog)
|
@objc(VDSTooltipDialog)
|
||||||
open class TooltipDialog: View, UIScrollViewDelegate, ParentViewProtocol {
|
open class TooltipDialog: View, UIScrollViewDelegate, ParentViewProtocol {
|
||||||
|
|
||||||
|
|||||||
@ -187,4 +187,10 @@ extension UIColor {
|
|||||||
guard let found else { return nil}
|
guard let found else { return nil}
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var surface: Surface {
|
||||||
|
var greyScale: CGFloat = 0
|
||||||
|
getWhite(&greyScale, alpha: nil)
|
||||||
|
return greyScale < 0.5 ? .dark : .light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -192,14 +192,4 @@ extension UIColor {
|
|||||||
}
|
}
|
||||||
self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
|
self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func isDark() -> Bool {
|
|
||||||
var white: CGFloat = 0
|
|
||||||
var alpha: CGFloat = 0
|
|
||||||
if getWhite(&white, alpha: &alpha) {
|
|
||||||
return white < 0.5
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -647,14 +647,7 @@ public enum LayoutDistribution: String, CaseIterable {
|
|||||||
case fillProportionally
|
case fillProportionally
|
||||||
}
|
}
|
||||||
|
|
||||||
extension LayoutConstraintable where Self: UIView {
|
|
||||||
public var constrainedWidth: CGFloat {
|
|
||||||
horizontalPinnedWidth() ?? (superview?.frame.size.width ?? frame.size.width)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension LayoutConstraintable {
|
extension LayoutConstraintable {
|
||||||
|
|
||||||
public func removeConstraints() {
|
public func removeConstraints() {
|
||||||
guard let view = self as? UIView, let superview = view.superview else { return }
|
guard let view = self as? UIView, let superview = view.superview else { return }
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +1,8 @@
|
|||||||
1.0.76
|
|
||||||
----------------
|
|
||||||
- ONEAPP-11355 - ListUnordered - Finished Development
|
|
||||||
- CXTDT-630735 - PriceLockup - Accessibility
|
|
||||||
- CXTDT-626164 - FootnoteGroup - Dark mode
|
|
||||||
- CXTDT-626180 - FootnoteItem - Symbol type padding
|
|
||||||
- CXTDT-586383 - Table - Line style can be selected for each row.
|
|
||||||
|
|
||||||
1.0.75
|
|
||||||
----------------
|
|
||||||
- CXTDT-624895 - Badge - Custom FillColor and TextColor
|
|
||||||
- CXTDT-578885 - Table - Setting appropriate accessiblity label for each cell.
|
|
||||||
|
|
||||||
1.0.74
|
|
||||||
----------------
|
|
||||||
- CXTDT-591307 - DatePicker - Accessibility - #1 & #2
|
|
||||||
- CXTDT-577374 - Label - Spanish - Accent mark displays incorrectly
|
|
||||||
- CXTDT-595956 - Tilelet - Text Position does not work on Light surface
|
|
||||||
- CXTDT-595952 - Tilelet - Aspect Ratio Width/height setting
|
|
||||||
- CXTDT-595970 - Tilelet - Subtitle size options missing
|
|
||||||
- CXTDT-595965 - Tilelet - Incorrect Mobile Padding
|
|
||||||
- ONEAPP-10583 - Modal - Finished Development
|
|
||||||
|
|
||||||
1.0.73
|
1.0.73
|
||||||
----------------
|
----------------
|
||||||
- CXTDT-597984 - Table - Text wrap
|
- CXTDT-597984 - Table - Text wrap
|
||||||
- CXTDT-586372 - Table - Stripes defect
|
- CXTDT-586372 - Table - Stripes defect
|
||||||
- CXTDT-586383 - Table - Line style
|
- CXTDT-586383 - Table - Line style
|
||||||
- CXTDT-603719 - Carousel - Pagination caret icon
|
|
||||||
|
|
||||||
1.0.72
|
1.0.72
|
||||||
----------------
|
----------------
|
||||||
|
|||||||
@ -11,72 +11,209 @@ import VDSCoreTokens
|
|||||||
|
|
||||||
//MARK: Definitions
|
//MARK: Definitions
|
||||||
extension TextStyle {
|
extension TextStyle {
|
||||||
internal enum Style: String, CaseIterable {
|
|
||||||
case boldFeatureXLarge
|
|
||||||
case featureXLarge
|
|
||||||
case boldFeatureLarge
|
|
||||||
case featureLarge
|
|
||||||
case boldFeatureMedium
|
|
||||||
case featureMedium
|
|
||||||
case boldFeatureSmall
|
|
||||||
case featureSmall
|
|
||||||
case boldFeatureXSmall
|
|
||||||
case featureXSmall
|
|
||||||
case boldTitle2XLarge
|
|
||||||
case title2XLarge
|
|
||||||
case boldTitleXLarge
|
|
||||||
case titleXLarge
|
|
||||||
case boldTitleLarge
|
|
||||||
case titleLarge
|
|
||||||
case boldTitleMedium
|
|
||||||
case titleMedium
|
|
||||||
case boldTitleSmall
|
|
||||||
case titleSmall
|
|
||||||
case boldBodyLarge
|
|
||||||
case bodyLarge
|
|
||||||
case boldBodyMedium
|
|
||||||
case bodyMedium
|
|
||||||
case boldBodySmall
|
|
||||||
case bodySmall
|
|
||||||
case boldMicro
|
|
||||||
case micro
|
|
||||||
}
|
|
||||||
|
|
||||||
// Static properties for different text styles
|
// Static properties for different text styles
|
||||||
public static var boldFeatureXLarge: TextStyle { Provider.style(for: .boldFeatureXLarge) }
|
|
||||||
public static var featureXLarge: TextStyle { Provider.style(for: .featureXLarge) }
|
|
||||||
public static var boldFeatureLarge: TextStyle { Provider.style(for: .boldFeatureLarge) }
|
|
||||||
public static var featureLarge: TextStyle { Provider.style(for: .featureLarge) }
|
|
||||||
public static var boldFeatureMedium: TextStyle { Provider.style(for: .boldFeatureMedium) }
|
|
||||||
public static var featureMedium: TextStyle { Provider.style(for: .featureMedium) }
|
|
||||||
public static var boldFeatureSmall: TextStyle { Provider.style(for: .boldFeatureSmall) }
|
|
||||||
public static var featureSmall: TextStyle { Provider.style(for: .featureSmall) }
|
|
||||||
public static var boldFeatureXSmall: TextStyle { Provider.style(for: .boldFeatureXSmall) }
|
|
||||||
public static var featureXSmall: TextStyle { Provider.style(for: .featureXSmall) }
|
|
||||||
public static var boldTitle2XLarge: TextStyle { Provider.style(for: .boldTitle2XLarge) }
|
|
||||||
public static var title2XLarge: TextStyle { Provider.style(for: .title2XLarge) }
|
|
||||||
public static var boldTitleXLarge: TextStyle { Provider.style(for: .boldTitleXLarge) }
|
|
||||||
public static var titleXLarge: TextStyle { Provider.style(for: .titleXLarge) }
|
|
||||||
public static var boldTitleLarge: TextStyle { Provider.style(for: .boldTitleLarge) }
|
|
||||||
public static var titleLarge: TextStyle { Provider.style(for: .titleLarge) }
|
|
||||||
public static var boldTitleMedium: TextStyle { Provider.style(for: .boldTitleMedium) }
|
|
||||||
public static var titleMedium: TextStyle { Provider.style(for: .titleMedium) }
|
|
||||||
public static var boldTitleSmall: TextStyle { Provider.style(for: .boldTitleSmall) }
|
|
||||||
public static var titleSmall: TextStyle { Provider.style(for: .titleSmall) }
|
|
||||||
public static var boldBodyLarge: TextStyle { Provider.style(for: .boldBodyLarge) }
|
|
||||||
public static var bodyLarge: TextStyle { Provider.style(for: .bodyLarge) }
|
|
||||||
public static var boldBodyMedium: TextStyle { Provider.style(for: .boldBodyMedium) }
|
|
||||||
public static var bodyMedium: TextStyle { Provider.style(for: .bodyMedium) }
|
|
||||||
public static var boldBodySmall: TextStyle { Provider.style(for: .boldBodySmall) }
|
|
||||||
public static var bodySmall: TextStyle { Provider.style(for: .bodySmall) }
|
|
||||||
public static var boldMicro: TextStyle { Provider.style(for: .boldMicro) }
|
|
||||||
public static var micro: TextStyle { Provider.style(for: .micro) }
|
|
||||||
|
|
||||||
public static var allCases: [TextStyle] { Style.allCases.compactMap { Provider.style(for: $0) } }
|
public static let boldFeatureXLarge = TextStyle(rawValue: "boldFeatureXLarge",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4))
|
||||||
|
|
||||||
|
public static let featureXLarge = TextStyle(rawValue: "featureXLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4))
|
||||||
|
|
||||||
|
public static let boldFeatureLarge = TextStyle(rawValue: "boldFeatureLarge",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2))
|
||||||
|
|
||||||
|
public static let featureLarge = TextStyle(rawValue: "featureLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2))
|
||||||
|
|
||||||
|
public static let boldFeatureMedium = TextStyle(rawValue: "boldFeatureMedium",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -4: -2))
|
||||||
|
|
||||||
|
public static let featureMedium = TextStyle(rawValue: "featureMedium",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -4: -2))
|
||||||
|
|
||||||
|
public static let boldFeatureSmall = TextStyle(rawValue: "boldFeatureSmall",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
|
||||||
|
|
||||||
|
public static let featureSmall = TextStyle(rawValue: "featureSmall",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
|
||||||
|
|
||||||
|
public static let boldFeatureXSmall = TextStyle(rawValue: "boldFeatureXSmall",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
|
||||||
|
|
||||||
|
public static let featureXSmall = TextStyle(rawValue: "featureXSmall",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
|
||||||
|
|
||||||
|
public static let boldTitle2XLarge = TextStyle(rawValue: "boldTitle2XLarge",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
|
||||||
|
|
||||||
|
public static let title2XLarge = TextStyle(rawValue: "title2XLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
||||||
|
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
|
||||||
|
|
||||||
|
public static let boldTitleXLarge = TextStyle(rawValue: "boldTitleXLarge",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36)
|
||||||
|
|
||||||
|
public static let titleXLarge = TextStyle(rawValue: "titleXLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingSemiwide)
|
||||||
|
|
||||||
|
public static let boldTitleLarge = TextStyle(rawValue: "boldTitleLarge",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28)
|
||||||
|
|
||||||
|
public static let titleLarge = TextStyle(rawValue: "titleLarge",
|
||||||
|
fontFace: UIDevice.isIPad ? .dsLight : .edsRegular,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28,
|
||||||
|
letterSpacing: UIDevice.isIPad ? VDSTypography.letterSpacingSemiwide : 0)
|
||||||
|
|
||||||
|
public static let boldTitleMedium = TextStyle(rawValue: "boldTitleMedium",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24)
|
||||||
|
|
||||||
|
public static let titleMedium = TextStyle(rawValue: "titleMedium",
|
||||||
|
fontFace: .edsRegular,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24)
|
||||||
|
|
||||||
|
public static let boldTitleSmall = TextStyle(rawValue: "boldTitleSmall",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20)
|
||||||
|
|
||||||
|
public static let titleSmall = TextStyle(rawValue: "titleSmall",
|
||||||
|
fontFace: .edsRegular,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20)
|
||||||
|
|
||||||
|
public static let boldBodyLarge = TextStyle(rawValue: "boldBodyLarge",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: VDSTypography.fontSizeBody16,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody20,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingWide)
|
||||||
|
|
||||||
|
public static let bodyLarge = TextStyle(rawValue: "bodyLarge",
|
||||||
|
fontFace: .edsRegular,
|
||||||
|
pointSize: VDSTypography.fontSizeBody16,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody20,
|
||||||
|
letterSpacing:VDSTypography.letterSpacingWide)
|
||||||
|
|
||||||
|
public static let boldBodyMedium = TextStyle(rawValue: "boldBodyMedium",
|
||||||
|
fontFace: .edsBold,
|
||||||
|
pointSize: VDSTypography.fontSizeBody14,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody18,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingWide)
|
||||||
|
|
||||||
|
public static let bodyMedium = TextStyle(rawValue: "bodyMedium",
|
||||||
|
fontFace: .edsRegular,
|
||||||
|
pointSize: VDSTypography.fontSizeBody14,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody18,
|
||||||
|
letterSpacing: VDSTypography.letterSpacingWide)
|
||||||
|
|
||||||
|
public static let boldBodySmall = TextStyle(rawValue: "boldBodySmall",
|
||||||
|
fontFace: .etxBold,
|
||||||
|
pointSize: VDSTypography.fontSizeBody12,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody16)
|
||||||
|
|
||||||
|
public static let bodySmall = TextStyle(rawValue: "bodySmall",
|
||||||
|
fontFace: .etxRegular,
|
||||||
|
pointSize: VDSTypography.fontSizeBody12,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody16)
|
||||||
|
|
||||||
|
public static let boldMicro = TextStyle(rawValue: "boldMicro",
|
||||||
|
fontFace: .etxBold,
|
||||||
|
pointSize: VDSTypography.fontSizeMicro11,
|
||||||
|
lineHeight: VDSTypography.lineHeightMicro16)
|
||||||
|
|
||||||
|
public static let micro = TextStyle(rawValue: "micro",
|
||||||
|
fontFace: .etxRegular,
|
||||||
|
pointSize: VDSTypography.fontSizeMicro11,
|
||||||
|
lineHeight: VDSTypography.lineHeightMicro16)
|
||||||
|
|
||||||
|
public static var allCases: [TextStyle] {
|
||||||
|
return [
|
||||||
|
featureXLarge,
|
||||||
|
boldFeatureXLarge,
|
||||||
|
featureLarge,
|
||||||
|
boldFeatureLarge,
|
||||||
|
featureMedium,
|
||||||
|
boldFeatureMedium,
|
||||||
|
featureSmall,
|
||||||
|
boldFeatureSmall,
|
||||||
|
featureXSmall,
|
||||||
|
boldFeatureXSmall,
|
||||||
|
title2XLarge,
|
||||||
|
boldTitle2XLarge,
|
||||||
|
titleXLarge,
|
||||||
|
boldTitleXLarge,
|
||||||
|
titleLarge,
|
||||||
|
boldTitleLarge,
|
||||||
|
titleMedium,
|
||||||
|
boldTitleMedium,
|
||||||
|
titleSmall,
|
||||||
|
boldTitleSmall,
|
||||||
|
bodyLarge,
|
||||||
|
boldBodyLarge,
|
||||||
|
bodyMedium,
|
||||||
|
boldBodyMedium,
|
||||||
|
bodySmall,
|
||||||
|
boldBodySmall,
|
||||||
|
micro,
|
||||||
|
boldMicro
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
public static func convert(font: UIFont) -> TextStyle {
|
public static func convert(font: UIFont) -> TextStyle {
|
||||||
guard let found = allCases.first(where: { font.fontName == $0.fontFace.fontName && font.pointSize == $0.pointSize} ) else {
|
guard let found = allCases.first(where: { font.fontName == $0.fontFace.fontName && font.pointSize == $0.pointSize} ) else {
|
||||||
return TextStyle(rawValue: "Custom\(font.fontName)", fontFace: .custom(font), pointSize: font.pointSize, lineHeight: min(font.lineHeight, font.pointSize))
|
return TextStyle(rawValue: "Custom\(font.fontName)", fontFace: .custom(font), pointSize: font.pointSize)
|
||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,246 +0,0 @@
|
|||||||
//
|
|
||||||
// Typography+StyleProvider.swift
|
|
||||||
// VDS
|
|
||||||
//
|
|
||||||
// Created by Matt Bruce on 9/25/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import VDSCoreTokens
|
|
||||||
|
|
||||||
extension TextStyle {
|
|
||||||
// Class responsible for providing the correct TextStyles based on language
|
|
||||||
public class Provider {
|
|
||||||
|
|
||||||
// Base styles for English (default)
|
|
||||||
private static let baseStyles: [Style: TextStyle] = [
|
|
||||||
.boldFeatureXLarge: TextStyle(rawValue: Style.boldFeatureXLarge.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4)),
|
|
||||||
|
|
||||||
.featureXLarge: TextStyle(rawValue: Style.featureXLarge.rawValue,
|
|
||||||
fontFace: .dsLight,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4)),
|
|
||||||
|
|
||||||
.boldFeatureLarge: TextStyle(rawValue: Style.boldFeatureLarge.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2)),
|
|
||||||
|
|
||||||
.featureLarge: TextStyle(rawValue: Style.featureLarge.rawValue,
|
|
||||||
fontFace: .dsLight,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2)),
|
|
||||||
|
|
||||||
.boldFeatureMedium: TextStyle(rawValue: Style.boldFeatureMedium.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -4: -2)),
|
|
||||||
|
|
||||||
.featureMedium: TextStyle(rawValue: Style.featureMedium.rawValue,
|
|
||||||
fontFace: .dsLight,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -4: -2)),
|
|
||||||
|
|
||||||
.boldFeatureSmall: TextStyle(rawValue: Style.boldFeatureSmall.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
|
|
||||||
|
|
||||||
.featureSmall: TextStyle(rawValue: Style.featureSmall.rawValue,
|
|
||||||
fontFace: .dsLight,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
|
|
||||||
|
|
||||||
.boldFeatureXSmall: TextStyle(rawValue: Style.boldFeatureXSmall.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
|
|
||||||
|
|
||||||
.featureXSmall: TextStyle(rawValue: Style.featureXSmall.rawValue,
|
|
||||||
fontFace: .dsLight,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
|
|
||||||
|
|
||||||
.boldTitle2XLarge: TextStyle(rawValue: Style.boldTitle2XLarge.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
|
|
||||||
|
|
||||||
.title2XLarge: TextStyle(rawValue: Style.title2XLarge.rawValue,
|
|
||||||
fontFace: .dsLight,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingSemiwide,
|
|
||||||
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
|
|
||||||
|
|
||||||
.boldTitleXLarge: TextStyle(rawValue: Style.boldTitleXLarge.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36),
|
|
||||||
|
|
||||||
.titleXLarge: TextStyle(rawValue: Style.titleXLarge.rawValue,
|
|
||||||
fontFace: .dsLight,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingSemiwide),
|
|
||||||
|
|
||||||
.boldTitleLarge: TextStyle(rawValue: Style.boldTitleLarge.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28),
|
|
||||||
|
|
||||||
.titleLarge: TextStyle(rawValue: Style.titleLarge.rawValue,
|
|
||||||
fontFace: UIDevice.isIPad ? .dsLight : .edsRegular,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28,
|
|
||||||
letterSpacing: UIDevice.isIPad ? VDSTypography.letterSpacingSemiwide : 0),
|
|
||||||
|
|
||||||
.boldTitleMedium: TextStyle(rawValue: Style.boldTitleMedium.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24),
|
|
||||||
|
|
||||||
.titleMedium: TextStyle(rawValue: Style.titleMedium.rawValue,
|
|
||||||
fontFace: .edsRegular,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24),
|
|
||||||
|
|
||||||
.boldTitleSmall: TextStyle(rawValue: Style.boldTitleSmall.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20),
|
|
||||||
|
|
||||||
.titleSmall: TextStyle(rawValue: Style.titleSmall.rawValue,
|
|
||||||
fontFace: .edsRegular,
|
|
||||||
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
|
|
||||||
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20),
|
|
||||||
|
|
||||||
.boldBodyLarge: TextStyle(rawValue: Style.boldBodyLarge.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: VDSTypography.fontSizeBody16,
|
|
||||||
lineHeight: VDSTypography.lineHeightBody20,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingWide),
|
|
||||||
|
|
||||||
.bodyLarge: TextStyle(rawValue: Style.bodyLarge.rawValue,
|
|
||||||
fontFace: .edsRegular,
|
|
||||||
pointSize: VDSTypography.fontSizeBody16,
|
|
||||||
lineHeight: VDSTypography.lineHeightBody20,
|
|
||||||
letterSpacing:VDSTypography.letterSpacingWide),
|
|
||||||
|
|
||||||
.boldBodyMedium: TextStyle(rawValue: Style.boldBodyMedium.rawValue,
|
|
||||||
fontFace: .edsBold,
|
|
||||||
pointSize: VDSTypography.fontSizeBody14,
|
|
||||||
lineHeight: VDSTypography.lineHeightBody18,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingWide),
|
|
||||||
|
|
||||||
.bodyMedium: TextStyle(rawValue: Style.bodyMedium.rawValue,
|
|
||||||
fontFace: .edsRegular,
|
|
||||||
pointSize: VDSTypography.fontSizeBody14,
|
|
||||||
lineHeight: VDSTypography.lineHeightBody18,
|
|
||||||
letterSpacing: VDSTypography.letterSpacingWide),
|
|
||||||
|
|
||||||
.boldBodySmall: TextStyle(rawValue: Style.boldBodySmall.rawValue,
|
|
||||||
fontFace: .etxBold,
|
|
||||||
pointSize: VDSTypography.fontSizeBody12,
|
|
||||||
lineHeight: VDSTypography.lineHeightBody16),
|
|
||||||
|
|
||||||
.bodySmall: TextStyle(rawValue: Style.bodySmall.rawValue,
|
|
||||||
fontFace: .etxRegular,
|
|
||||||
pointSize: VDSTypography.fontSizeBody12,
|
|
||||||
lineHeight: VDSTypography.lineHeightBody16),
|
|
||||||
|
|
||||||
.boldMicro: TextStyle(rawValue: Style.boldMicro.rawValue,
|
|
||||||
fontFace: .etxBold,
|
|
||||||
pointSize: VDSTypography.fontSizeMicro11,
|
|
||||||
lineHeight: VDSTypography.lineHeightMicro16),
|
|
||||||
|
|
||||||
.micro: TextStyle(rawValue: Style.micro.rawValue,
|
|
||||||
fontFace: .etxRegular,
|
|
||||||
pointSize: VDSTypography.fontSizeMicro11,
|
|
||||||
lineHeight: VDSTypography.lineHeightMicro16)
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
// Spanish lineHeight overrides
|
|
||||||
private static let spanishLineHeightOverrides: [Style: CGFloat] = [
|
|
||||||
.boldFeatureXLarge: UIDevice.isIPad ? 156 : 104,
|
|
||||||
.featureXLarge: UIDevice.isIPad ? 156 : 104,
|
|
||||||
.boldFeatureLarge: UIDevice.isIPad ? 140 : 88,
|
|
||||||
.featureLarge: UIDevice.isIPad ? 140 : 88,
|
|
||||||
.boldFeatureMedium: UIDevice.isIPad ? 104 : 72,
|
|
||||||
.featureMedium: UIDevice.isIPad ? 104 : 72,
|
|
||||||
.boldFeatureSmall: UIDevice.isIPad ? 88 : 56,
|
|
||||||
.featureSmall: UIDevice.isIPad ? 88 : 56,
|
|
||||||
.boldFeatureXSmall: UIDevice.isIPad ? 72 : 48,
|
|
||||||
.featureXSmall: UIDevice.isIPad ? 72 : 48,
|
|
||||||
.boldTitle2XLarge: UIDevice.isIPad ? 72 : 48,
|
|
||||||
.title2XLarge: UIDevice.isIPad ? 72 : 48,
|
|
||||||
.boldTitleXLarge: UIDevice.isIPad ? 56 : 36,
|
|
||||||
.titleXLarge: UIDevice.isIPad ? 56 : 36
|
|
||||||
]
|
|
||||||
|
|
||||||
// Cache for the current styles based on the current language
|
|
||||||
private static var currentStyles: [Style: TextStyle] = [:]
|
|
||||||
|
|
||||||
// Function to get the style with conditional lineHeight adjustment
|
|
||||||
static func style(for key: Style) -> TextStyle {
|
|
||||||
DispatchQueue.once(block: { TextStyle.Provider.initialize() })
|
|
||||||
guard let style = currentStyles[key] else {
|
|
||||||
fatalError("TextStyle for \(key.rawValue) is not defined.")
|
|
||||||
}
|
|
||||||
return style
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update current styles only once when language changes
|
|
||||||
static func updateCurrentStyles() {
|
|
||||||
// Start with the base styles
|
|
||||||
currentStyles = baseStyles
|
|
||||||
|
|
||||||
// If the language is Spanish, apply the lineHeight overrides
|
|
||||||
if LanguageManager.currentLanguage == .spanish {
|
|
||||||
for (styleKey, spanishLineHeight) in spanishLineHeightOverrides {
|
|
||||||
if var style = currentStyles[styleKey] {
|
|
||||||
style = TextStyle(
|
|
||||||
rawValue: style.rawValue,
|
|
||||||
fontFace: style.fontFace,
|
|
||||||
pointSize: style.pointSize,
|
|
||||||
lineHeight: spanishLineHeight, // Apply the Spanish lineHeight
|
|
||||||
letterSpacing: style.letterSpacing,
|
|
||||||
edgeInsets: style.edgeInsets
|
|
||||||
)
|
|
||||||
currentStyles[styleKey] = style
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial setup to populate the current styles based on the initial language
|
|
||||||
static func initialize() {
|
|
||||||
updateCurrentStyles()
|
|
||||||
Style.allCases.forEach { style in
|
|
||||||
let found = Provider.currentStyles[style]
|
|
||||||
assert(found != nil, "\(style.rawValue) has not been set in the TextStyleProvider.baseStyles")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -32,16 +32,12 @@ Using the system allows designers and developers to collaborate more easily and
|
|||||||
- ``CheckboxItem``
|
- ``CheckboxItem``
|
||||||
- ``CheckboxGroup``
|
- ``CheckboxGroup``
|
||||||
- ``DropdownSelect``
|
- ``DropdownSelect``
|
||||||
- ``FootnoteItem``
|
|
||||||
- ``FootnoteGroup``
|
|
||||||
- ``Icon``
|
- ``Icon``
|
||||||
- ``InputStepper``
|
- ``InputStepper``
|
||||||
- ``InputField``
|
- ``InputField``
|
||||||
- ``Label``
|
- ``Label``
|
||||||
- ``Line``
|
- ``Line``
|
||||||
- ``ListUnordered``
|
|
||||||
- ``Loader``
|
- ``Loader``
|
||||||
- ``Modal``
|
|
||||||
- ``Notification``
|
- ``Notification``
|
||||||
- ``Pagination``
|
- ``Pagination``
|
||||||
- ``PriceLockup``
|
- ``PriceLockup``
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user