Compare commits

...

91 Commits

Author SHA1 Message Date
98dde01e18 Merge branch 'develop' of ssh://git@192.168.1.128:220/mbrucedogs/vds_ios.git into develop 2025-01-23 13:25:16 -06:00
78dd2d5df8 removed obj-c members
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
2025-01-23 13:24:48 -06:00
58850aeb6e Merge branch 'develop' into vasavk/listUnordered 2025-01-06 17:16:27 -06:00
Sumanth Nadigadda
15a53964c5 Adding release note for CXTDT-586383 changes 2024-10-23 13:08:09 +05:30
Bruce, Matt R
762868609b Merge branch 'bugfix/CXTDT-626180' into 'develop'
Footnote Item - Padding issue fixed for the Symbol type ‘none'

See merge request BPHV_MIPS/vds_ios!320
2024-10-22 13:20:02 +00:00
Vasavi Kanamarlapudi
e256dfd209 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios into vasavk/listUnordered
# Conflicts:
#	VDS/SupportingFiles/ReleaseNotes.txt
2024-10-22 14:48:36 +05:30
Vasavi Kanamarlapudi
a1236df9a9 Digital ACT-191 CXTDT-626180 defect: Footnote Item - Padding issue fixed for the Symbol type ‘none'. 2024-10-22 14:43:36 +05:30
Bruce, Matt R
539f10ffbf Merge branch 'bugfix/priceLockup' into 'develop'
Fixed the PriceLockup accessibility Issue - CXTDT-630735

See merge request BPHV_MIPS/vds_ios!318
2024-10-21 14:30:23 +00:00
Bruce, Matt R
cc530e5903 Merge branch 'develop' into 'bugfix/priceLockup'
# Conflicts:
#   VDS/SupportingFiles/ReleaseNotes.txt
2024-10-21 14:29:53 +00:00
Bruce, Matt R
482212e88c Merge branch 'bugfix/CXTDT-626164-footnoteGroup' into 'develop'
Fixed the defect CXTDT-626164 of FootnoteGroup

See merge request BPHV_MIPS/vds_ios!319
2024-10-21 14:28:34 +00:00
Vasavi Kanamarlapudi
47409d2905 Digital ACT-191 CXTDT-626164 defect: FootnoteGroup - Text not showing in Dark Mode 2024-10-21 15:26:58 +05:30
Vasavi Kanamarlapudi
16516fbeed Digital ACT-191 ONEAPP-11355 story: updated release notes 2024-10-21 12:47:43 +05:30
Vasavi Kanamarlapudi
484d12626e Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios into vasavk/listUnordered 2024-10-21 12:44:59 +05:30
Vasavi Kanamarlapudi
9856c0a482 Digital ACT-191 CXTDT-630735 defect: PriceLockup accessibility - to render equivalent information for the strike through price visually represents. 2024-10-21 12:39:14 +05:30
Vasavi Kanamarlapudi
4797e5a7f7 Digital ACT-191 ONEAPP-11355 story: adjusted alignments 2024-10-19 14:38:03 +05:30
Bruce, Matt R
942834ec3e Merge branch 'mbruce/bugfix' into 'develop'
updated version

See merge request BPHV_MIPS/vds_ios!316
2024-10-18 21:31:53 +00:00
Vasavi Kanamarlapudi
62aedc7c5a Digital ACT-191 ONEAPP-11355 story: changes done as per anatomy 2024-10-18 19:52:55 +05:30
Matt Bruce
2e3524cde6 updated version
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-17 16:19:41 -05:00
Bruce, Matt R
735749eaa5 Merge branch 'mbruce/bugfix' into 'develop'
bug fixes

See merge request BPHV_MIPS/vds_ios!315
2024-10-16 20:17:26 +00:00
Matt Bruce
4e581491fa added initial actionable elements
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-16 15:16:05 -05:00
Bruce, Matt R
4fbbe485f7 Merge branch 'bugfix/CXTDT-578885' into 'develop'
Fix for CXTDT-578885, Settings appropriate accessibility label for each cell

See merge request BPHV_MIPS/vds_ios!314
2024-10-16 16:17:46 +00:00
Sumanth Nadigadda
216971b878 Fix for CXTDT-578885, Settings appropriate accessibility label for each cell 2024-10-16 21:37:01 +05:30
Matt Bruce
d66d4d0e26 removed surface since it isn't used anywhere
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-16 08:39:48 -05:00
Vasavi Kanamarlapudi
c352fbaac9 Digital ACT-191 ONEAPP-11355 story: added list unordered item model 2024-10-16 14:26:01 +05:30
Vasavi Kanamarlapudi
759ef0db5b Digital ACT-191 ONEAPP-11355 story: added change log and added class for docs 2024-10-16 14:24:45 +05:30
Vasavi Kanamarlapudi
dc7dbffcf6 Digital ACT-191 ONEAPP-11355 story: added new file for List Unordered 2024-10-16 14:23:30 +05:30
Bruce, Matt R
a019c1ba36 Merge branch 'mbruce/bugfix' into 'develop'
fixed issue with icon

See merge request BPHV_MIPS/vds_ios!313
2024-10-15 20:12:05 +00:00
Matt Bruce
fc6b2991b8 fixed issue with icon
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-14 13:23:16 -05:00
Hedden, Kyle Matthew
dd437d7423 Merge branch 'feature/CXTDT-624895-Badge-Color-Updates' into 'develop'
VDS - iOS Badge - Include ability to select custom color for Label and Background

See merge request BPHV_MIPS/vds_ios!311
2024-10-09 13:04:03 +00:00
Matt Bruce
025700a632 made internal since there is a duplicate in coreUI that is obj-c
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-08 09:18:51 -05:00
Matt Bruce
50117f3f2f updated to include badge color changes to dependent components
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-07 15:58:56 -05:00
Matt Bruce
8057b16e5b added badge coloring in text/fill
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-07 15:58:30 -05:00
Bruce, Matt R
1728592bff Merge branch 'mbruce/bugfix' into 'develop'
mreged in Modal

See merge request BPHV_MIPS/vds_ios!310
2024-10-04 19:14:55 +00:00
Matt Bruce
a336066387 updated version
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-04 14:07:12 -05:00
Matt Bruce
049234831f updated notes
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-04 14:04:05 -05:00
Matt Bruce
dc83d1f565 mreged in Modal
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-04 13:55:20 -05:00
Bruce, Matt R
92a80b6496 Merge branch 'mbruce/modal' into 'develop'
removed width/height contraints in dialog and pushed down to the viewcontroller.

See merge request BPHV_MIPS/vds_ios!309
2024-10-04 18:47:19 +00:00
Matt Bruce
83ce02e879 updated spacing issue
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-04 13:46:43 -05:00
Bruce, Matt R
9f2da6f072 Merge branch 'bugfix/UIFont-Converter' into 'develop'
updated the UIFont to TextStyle conversion

See merge request BPHV_MIPS/vds_ios!307
2024-10-04 17:00:05 +00:00
Matt Bruce
c91da2189c updated the UIFont to TextStyle conversion
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-04 11:59:05 -05:00
Bruce, Matt R
2febe4595c Merge branch 'bugfix/TextStyleLabelAttribute' into 'develop'
fixed bug in TextStyle Attribute dealing with lineHeight and baseline

See merge request BPHV_MIPS/vds_ios!306
2024-10-03 21:04:11 +00:00
Matt Bruce
c68faaec31 fixed bug in TextStyle Attribute dealing with lineHeight and baseline
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-03 15:09:16 -05:00
Matt Bruce
0aab83c4cb Merge branch 'vasavk/modal' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios.git into mbruce/modal 2024-10-03 09:19:29 -05:00
Vasavi Kanamarlapudi
ff125d388d Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios into vasavk/modal 2024-10-03 12:50:04 +05:30
Matt Bruce
f741b3df8b removed width/height contraints in dialog and pushed down to the viewcontroller.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-01 16:32:17 -05:00
Vasavi Kanamarlapudi
a3a714dfc1 Digital ACT-191 ONEAPP-10928 story: documentation changes 2024-09-27 19:47:55 +05:30
Vasavi Kanamarlapudi
b210135566 Digital ACT-191 ONEAPP-10928 story: show/hide close button based on flag 2024-09-27 18:58:53 +05:30
Vasavi Kanamarlapudi
81725ffdeb Digital ACT-191 ONEAPP-10928 story: Modal to be displayed at full screen if fullScreenDialog true 2024-09-27 18:11:54 +05:30
Vasavi Kanamarlapudi
08be77242d Digital ACT-191 ONEAPP-10928 story: onClick for close button 2024-09-27 17:15:33 +05:30
Vasavi Kanamarlapudi
8a63ea5c75 Digital ACT-191 ONEAPP-10928 story: loading button data if provided 2024-09-27 17:05:19 +05:30
Vasavi Kanamarlapudi
e71b94bc4f Digital ACT-191 ONEAPP-10928 story: resolved constraint conflicts 2024-09-26 13:40:35 +05:30
Bruce, Matt R
183630f6b5 Merge branch 'mbruce/bugfix' into 'develop'
bugs

See merge request BPHV_MIPS/vds_ios!304
2024-09-25 21:31:44 +00:00
Matt Bruce
c17e74dea0 first cut of language
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-25 15:03:14 -05:00
Vasavi Kanamarlapudi
12ad80643d Digital ACT-191 ONEAPP-10928 story: documentation changes for modal dialog 2024-09-25 18:15:27 +05:30
Vasavi Kanamarlapudi
4d5704d47b Digital ACT-191 ONEAPP-10928 story: content text style and surface updates 2024-09-25 16:08:13 +05:30
Vasavi Kanamarlapudi
56155abbb0 Digital ACT-191 ONEAPP-10928 story: updated modal with alignments and spacing 2024-09-25 12:02:33 +05:30
Matt Bruce
821b06360e CXTDT-595965 - Tilelet - Incorrect Mobile Padding
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-24 15:25:14 -05:00
Matt Bruce
663c6072be CXTDT-595956 - Tilelet - Text Position does not work on Light surface
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-24 14:55:09 -05:00
Matt Bruce
d5cca1626e fixed width issue
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-24 14:54:19 -05:00
Matt Bruce
5e932000da updated tilelet
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-24 14:54:08 -05:00
Vasavi Kanamarlapudi
3c1caa7f5a Digital ACT-191 ONEAPP-10928 story: launching modal with fullscreen for mobile 2024-09-24 10:52:09 +05:30
Matt Bruce
c39a89a3f3 CXTDT-591307 - DatePicker - Accessibility - #1 & #2
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 16:10:37 -05:00
Bruce, Matt R
cb37d80f65 Merge branch 'mbruce/bugfix' into 'develop'
Width Updates

See merge request BPHV_MIPS/vds_ios!303
2024-09-20 19:24:17 +00:00
Matt Bruce
ebbbffc86e updated maxWidth
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 14:13:27 -05:00
Matt Bruce
26a3206639 removed constraints
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 14:13:11 -05:00
Matt Bruce
b5f3e37a4c constraindWidth
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 14:12:18 -05:00
Matt Bruce
ae460b8e4f removed
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 14:12:05 -05:00
Matt Bruce
905c5e9fb0 updated width
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 14:11:28 -05:00
Vasavi Kanamarlapudi
1f37597117 Digital ACT-191 ONEAPP-10928 story: added change log file 2024-09-20 13:04:47 +05:30
Vasavi Kanamarlapudi
f868389cb8 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios into vasavk/modal 2024-09-20 12:46:28 +05:30
Vasavi Kanamarlapudi
aa092023de Digital ACT-191 ONEAPP-10928 story: added class for docs 2024-09-20 12:40:57 +05:30
Vasavi Kanamarlapudi
e951e82b88 Digital ACT-191 ONEAPP-10928 story: added new file for Modal 2024-09-20 12:39:41 +05:30
Bruce, Matt R
e77bbea163 Merge branch 'mbruce/bugfix' into 'develop'
rename class for docs

See merge request BPHV_MIPS/vds_ios!302
2024-09-19 19:35:37 +00:00
Matt Bruce
e1f88e600b fixed issue with SelectorItemBase
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-19 14:34:39 -05:00
Matt Bruce
8028c8a785 removed constraints and for this class to be setup correctly in its parent rather than doing it in the view. similar to how UIButton works. 2024-09-19 14:34:24 -05:00
Matt Bruce
58b83fc37f rename class for docs
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-19 14:33:31 -05:00
Bruce, Matt R
fe8fb7f3cc Merge branch 'vasavk/footnote' into 'develop'
VDS Brand 3.0 Footnote for IOS

See merge request BPHV_MIPS/vds_ios!299
2024-09-18 20:16:24 +00:00
Matt Bruce
8ce9108d45 refactored the adding of footnotes similar to the Tabs
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-18 15:14:39 -05:00
Matt Bruce
9f6c115f50 made internal since only group uses this
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-18 15:00:27 -05:00
Vasavi Kanamarlapudi
2854aea8c2 refactored naming
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-18 14:56:04 -05:00
Vasavi Kanamarlapudi
e08de8fb3e Digital ACT-191 ONEAPP-10586 story: alignment changes to stackview 2024-09-12 18:26:21 +05:30
Vasavi Kanamarlapudi
9b885da7ca using .isHidden feature 2024-09-12 15:46:32 +05:30
Vasavi Kanamarlapudi
09351db136 Digital ACT-191 ONEAPP-10586 story: updated symbolType to use as String, camelCase applied to footnoteItems 2024-09-12 13:26:06 +05:30
Hedden, Kyle Matthew
6df8932d5d Merge branch 'bugfix/toggleAlignment' into 'develop'
Fix toggle alignment issue

See merge request BPHV_MIPS/vds_ios!300
2024-09-06 16:18:05 +00:00
Xi Zhang
f27f04c23d Fix toggle alignment issue 2024-09-04 15:40:07 -04:00
Vasavi Kanamarlapudi
e22b64095b Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios into vasavk/footnote
# Conflicts:
#	VDS.xcodeproj/project.pbxproj
2024-09-03 10:32:52 +05:30
Vasavi Kanamarlapudi
a0b139b0af Digital ACT-191 ONEAPP-10586 story: added footnote group and updating with footnote items 2024-09-02 11:33:59 +05:30
Vasavi Kanamarlapudi
73caedce5f Digital ACT-191 ONEAPP-10586 story: updating content as per configuration 2024-08-29 19:09:22 +05:30
Bruce, Matt R
973c45adbd Merge branch 'mbruce/bugfix' into 'develop'
Bug fixes

See merge request BPHV_MIPS/vds_ios!298
2024-08-27 20:28:14 +00:00
Vasavi Kanamarlapudi
9cbfe1d46a Digital ACT-191 ONEAPP-10586 story: added public properties 2024-08-22 17:08:12 +05:30
Vasavi Kanamarlapudi
7667908ffd Digital ACT-191 ONEAPP-10586 story: added new file for footnote 2024-08-21 18:32:40 +05:30
81 changed files with 2153 additions and 379 deletions

View File

@ -10,16 +10,25 @@
180636C72C29B0A400C92D86 /* InputStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 180636C62C29B0A400C92D86 /* InputStepper.swift */; }; 180636C72C29B0A400C92D86 /* InputStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 180636C62C29B0A400C92D86 /* InputStepper.swift */; };
180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */; }; 180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */; };
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */; }; 1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */; };
1818D04D2C9BD2170053E73C /* ModalDialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1818D04C2C9BD2170053E73C /* ModalDialogViewController.swift */; };
1818D04F2C9BD3F60053E73C /* ModalDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1818D04E2C9BD3F60053E73C /* ModalDialog.swift */; };
1818D0512C9BD4090053E73C /* ModalLaunchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1818D0502C9BD4090053E73C /* ModalLaunchable.swift */; };
1818D0532C9BD47C0053E73C /* ModalModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1818D0522C9BD47C0053E73C /* ModalModel.swift */; };
1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; }; 1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; };
183B16F32C78CF7C00BA6A10 /* CarouselSlotCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */; }; 183B16F32C78CF7C00BA6A10 /* CarouselSlotCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */; };
183B16F72C80B32200BA6A10 /* FootnoteGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */; };
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 */; };
@ -27,6 +36,8 @@
18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */; }; 18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */; };
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; }; 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; };
18B9763F2C11BA4A009271DF /* CarouselPaginationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */; }; 18B9763F2C11BA4A009271DF /* CarouselPaginationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */; };
18C0F9462C98175900E1DD71 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C0F9452C98175900E1DD71 /* Modal.swift */; };
18C0F94A2C9817C100E1DD71 /* ModalChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18C0F9492C9817C100E1DD71 /* ModalChangeLog.txt */; };
18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; }; 18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; };
18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */; }; 18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */; };
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
@ -60,6 +71,8 @@
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 */; };
@ -216,8 +229,13 @@
180636C82C29B0DF00C92D86 /* InputStepperLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = InputStepperLog.txt; sourceTree = "<group>"; }; 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = InputStepperLog.txt; sourceTree = "<group>"; };
1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselScrollbar.swift; sourceTree = "<group>"; }; 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselScrollbar.swift; sourceTree = "<group>"; };
1808BEBF2BA456B700129230 /* CarouselScrollbarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CarouselScrollbarChangeLog.txt; sourceTree = "<group>"; }; 1808BEBF2BA456B700129230 /* CarouselScrollbarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CarouselScrollbarChangeLog.txt; sourceTree = "<group>"; };
1818D04C2C9BD2170053E73C /* ModalDialogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalDialogViewController.swift; sourceTree = "<group>"; };
1818D04E2C9BD3F60053E73C /* ModalDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalDialog.swift; sourceTree = "<group>"; };
1818D0502C9BD4090053E73C /* ModalLaunchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalLaunchable.swift; sourceTree = "<group>"; };
1818D0522C9BD47C0053E73C /* ModalModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalModel.swift; sourceTree = "<group>"; };
1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = "<group>"; }; 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = "<group>"; };
183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselSlotCell.swift; sourceTree = "<group>"; }; 183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselSlotCell.swift; sourceTree = "<group>"; };
183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FootnoteGroup.swift; sourceTree = "<group>"; };
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>"; };
@ -225,10 +243,15 @@
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>"; };
@ -238,6 +261,8 @@
18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = "<group>"; }; 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = "<group>"; };
18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselPaginationModel.swift; sourceTree = "<group>"; }; 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselPaginationModel.swift; sourceTree = "<group>"; };
18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = "<group>"; }; 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = "<group>"; };
18C0F9452C98175900E1DD71 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = "<group>"; };
18C0F9492C9817C100E1DD71 /* ModalChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ModalChangeLog.txt; sourceTree = "<group>"; };
18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarIndicatorModel.swift; sourceTree = "<group>"; }; 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarIndicatorModel.swift; sourceTree = "<group>"; };
18FEA1B42BE0E63600A56439 /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = "<group>"; }; 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = "<group>"; };
18FEA1B82BE1301700A56439 /* CalendarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CalendarChangeLog.txt; sourceTree = "<group>"; }; 18FEA1B82BE1301700A56439 /* CalendarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CalendarChangeLog.txt; sourceTree = "<group>"; };
@ -252,7 +277,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 /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = "<group>"; }; 710607942B91A99500F2863F /* TileletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileletChangeLog.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>"; };
@ -280,6 +305,8 @@
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>"; };
@ -486,6 +513,16 @@
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 = (
@ -496,6 +533,16 @@
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 = (
@ -534,6 +581,19 @@
path = Carousel; path = Carousel;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
18C0F9442C980CE500E1DD71 /* Modal */ = {
isa = PBXGroup;
children = (
18C0F9452C98175900E1DD71 /* Modal.swift */,
1818D04E2C9BD3F60053E73C /* ModalDialog.swift */,
1818D04C2C9BD2170053E73C /* ModalDialogViewController.swift */,
1818D0502C9BD4090053E73C /* ModalLaunchable.swift */,
1818D0522C9BD47C0053E73C /* ModalModel.swift */,
18C0F9492C9817C100E1DD71 /* ModalChangeLog.txt */,
);
path = Modal;
sourceTree = "<group>";
};
440B84C82BD8E0CE004A732A /* Table */ = { 440B84C82BD8E0CE004A732A /* Table */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -709,11 +769,14 @@
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 */,
@ -797,12 +860,13 @@
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>";
@ -915,7 +979,7 @@
EA985BE72968951C00F2FF2E /* TileletTitleModel.swift */, EA985BE72968951C00F2FF2E /* TileletTitleModel.swift */,
EA985BE929689B6D00F2FF2E /* TileletSubTitleModel.swift */, EA985BE929689B6D00F2FF2E /* TileletSubTitleModel.swift */,
EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */, EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */,
710607942B91A99500F2863F /* TitleletChangeLog.txt */, 710607942B91A99500F2863F /* TileletChangeLog.txt */,
); );
path = Tilelet; path = Tilelet;
sourceTree = "<group>"; sourceTree = "<group>";
@ -970,6 +1034,7 @@
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>";
@ -1215,12 +1280,14 @@
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 */,
); );
@ -1279,6 +1346,7 @@
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 */,
@ -1295,6 +1363,7 @@
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 */,
@ -1305,10 +1374,12 @@
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 */,
@ -1321,6 +1392,7 @@
EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */, EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */,
71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */, 71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */,
EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */, EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */,
1818D0512C9BD4090053E73C /* ModalLaunchable.swift in Sources */,
EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */, EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */,
EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */, EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */,
EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */, EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */,
@ -1350,6 +1422,7 @@
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 */,
@ -1358,6 +1431,7 @@
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 */,
@ -1372,6 +1446,7 @@
EAF2F4892C2A1075007BFEDC /* AlertViewController.swift in Sources */, EAF2F4892C2A1075007BFEDC /* AlertViewController.swift in Sources */,
EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */, EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */,
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */, EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */,
1818D04F2C9BD3F60053E73C /* ModalDialog.swift in Sources */,
EAC58C0C2BED01D500BA39FA /* Telephone.swift in Sources */, EAC58C0C2BED01D500BA39FA /* Telephone.swift in Sources */,
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */, EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */, EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */,
@ -1386,6 +1461,7 @@
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 */,
@ -1423,6 +1499,7 @@
EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */, EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */,
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */, EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */, EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,
1818D04D2C9BD2170053E73C /* ModalDialogViewController.swift in Sources */,
EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */, EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */,
71FC86E02B973AE500700965 /* DropShadowConfiguration.swift in Sources */, 71FC86E02B973AE500700965 /* DropShadowConfiguration.swift in Sources */,
EA3362302891EB4A0071C351 /* Font.swift in Sources */, EA3362302891EB4A0071C351 /* Font.swift in Sources */,
@ -1431,6 +1508,7 @@
EAB5FEF12927F4AA00998C17 /* SelfSizingCollectionView.swift in Sources */, EAB5FEF12927F4AA00998C17 /* SelfSizingCollectionView.swift in Sources */,
184023452C61E7AD00A412C8 /* PriceLockup.swift in Sources */, 184023452C61E7AD00A412C8 /* PriceLockup.swift in Sources */,
EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */, EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */,
1818D0532C9BD47C0053E73C /* ModalModel.swift in Sources */,
EA3361A8288B23300071C351 /* UIColor.swift in Sources */, EA3361A8288B23300071C351 /* UIColor.swift in Sources */,
EA2DC9B42BE2C6FE004F58C5 /* TextField.swift in Sources */, EA2DC9B42BE2C6FE004F58C5 /* TextField.swift in Sources */,
EAC58C182BED0E2300BA39FA /* SecurityCode.swift in Sources */, EAC58C182BED0E2300BA39FA /* SecurityCode.swift in Sources */,
@ -1593,7 +1671,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 = 73; CURRENT_PROJECT_VERSION = 75;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
@ -1631,7 +1709,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 = 73; CURRENT_PROJECT_VERSION = 75;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;

View File

@ -10,7 +10,6 @@ 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 {
//-------------------------------------------------- //--------------------------------------------------

View File

@ -28,7 +28,6 @@ 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 {

View File

@ -43,13 +43,14 @@ 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 = .top $0.alignment = .fill
$0.axis = .vertical $0.axis = .vertical
} }
private var selectorStackView = UIStackView().with { private var selectorStackView = UIStackView().with {
$0.translatesAutoresizingMaskIntoConstraints = false $0.translatesAutoresizingMaskIntoConstraints = false
$0.alignment = .top $0.alignment = .fill
$0.axis = .horizontal $0.axis = .horizontal
} }
@ -171,10 +172,16 @@ 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(selectorView) selectorStackView.addArrangedSubview(selectorViewWrapper)
selectorStackView.addArrangedSubview(selectorLabelStackView) selectorStackView.addArrangedSubview(selectorLabelStackView)
selectorLabelStackView.addArrangedSubview(label) selectorLabelStackView.addArrangedSubview(label)
selectorLabelStackView.addArrangedSubview(childLabel) selectorLabelStackView.addArrangedSubview(childLabel)

View File

@ -10,7 +10,6 @@ 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 {

View File

@ -10,7 +10,6 @@ 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 {

View File

@ -8,7 +8,6 @@
import Foundation import Foundation
import UIKit import UIKit
@objcMembers
@objc(VDSClearPopoverViewController) @objc(VDSClearPopoverViewController)
open class ClearPopoverViewController: UIViewController, UIPopoverPresentationControllerDelegate { open class ClearPopoverViewController: UIViewController, UIPopoverPresentationControllerDelegate {

View File

@ -0,0 +1,63 @@
//
// 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
}
}
}

View File

@ -15,7 +15,6 @@ 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 {
@ -38,8 +37,16 @@ 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: String, CaseIterable { public enum FillColor: Equatable {
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
}
} }
//-------------------------------------------------- //--------------------------------------------------
@ -65,6 +72,8 @@ 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() }}
@ -93,38 +102,91 @@ 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: AnyColorable = { private var backgroundColorConfiguration = SurfaceColorConfiguration()
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 updateTextColorConfig() { public func updateColorConfig() {
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()
switch fillColor { func update(for color: UIColor) {
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) }
case .yellow, .white: if let textColor {
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false) switch textColor {
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true) case .token(let color):
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 .orange, .green, .blue: case .red, .black:
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: false) textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: true) textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, 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)
}
} }
} }
@ -179,7 +241,7 @@ open class Badge: View, ParentViewProtocol {
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
updateTextColorConfig() updateColorConfig()
updateMaxWidth() updateMaxWidth()
backgroundColor = backgroundColorConfiguration.getColor(self) backgroundColor = backgroundColorConfiguration.getColor(self)
@ -191,3 +253,29 @@ 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
}
}
}

View File

@ -11,7 +11,6 @@ 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 {

View File

@ -13,7 +13,6 @@ 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 {

View File

@ -13,7 +13,6 @@ 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 {

View File

@ -15,7 +15,6 @@ 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 {

View File

@ -11,7 +11,6 @@ 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 {

View File

@ -11,7 +11,6 @@ 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 {

View File

@ -16,7 +16,6 @@ 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 {
//-------------------------------------------------- //--------------------------------------------------

View File

@ -16,7 +16,6 @@ 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 {
//-------------------------------------------------- //--------------------------------------------------

View File

@ -11,7 +11,6 @@ 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 {

View File

@ -12,7 +12,6 @@ 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 {

View File

@ -12,7 +12,6 @@ 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 {

View File

@ -12,7 +12,6 @@ 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 {

View File

@ -12,7 +12,6 @@ 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 {

View File

@ -9,7 +9,6 @@ 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> {

View File

@ -4,7 +4,6 @@ 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> {
//-------------------------------------------------- //--------------------------------------------------
@ -183,6 +182,15 @@ 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 {

View File

@ -11,7 +11,6 @@ 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> {
//-------------------------------------------------- //--------------------------------------------------
@ -61,8 +60,9 @@ 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 = frame.size.width let frameWidth = constrainedWidth
return helperTextPlacement == .right ? (frameWidth - horizontalStackView.spacing) / 2 : frameWidth let halfWidth = (frameWidth - horizontalStackView.spacing) / 2
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.

View File

@ -0,0 +1,17 @@
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.

View File

@ -0,0 +1,165 @@
//
// 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()
}
}
}

View File

@ -0,0 +1,256 @@
//
// 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()
}
}
}

View File

@ -13,7 +13,6 @@ 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 {

View File

@ -11,7 +11,6 @@ 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> {
@ -331,8 +330,6 @@ open class InputStepper: EntryFieldBase<Int> {
stepperWidthConstraint?.deactivate() stepperWidthConstraint?.deactivate()
widthConstraint?.deactivate() widthConstraint?.deactivate()
trailingLessThanEqualsConstraint?.deactivate()
trailingEqualsConstraint?.deactivate()
var widthConstraintConstant: CGFloat? var widthConstraintConstant: CGFloat?
@ -350,9 +347,6 @@ 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.

View File

@ -39,6 +39,27 @@ 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 {

View File

@ -63,18 +63,15 @@ public struct TextStyleLabelAttribute: LabelAttributeModel {
//set lineHeight //set lineHeight
if textStyle.lineHeight > 0.0 { if textStyle.lineHeight > 0.0 {
let lineHeight = textStyle.lineHeight let lineHeight = textStyle.lineHeight + abs(textStyle.edgeInsets.bottom) + abs(textStyle.edgeInsets.top)
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 {
@ -87,3 +84,4 @@ public struct TextStyleLabelAttribute: LabelAttributeModel {
} }
} }
} }

View File

@ -12,7 +12,6 @@ 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 {

View File

@ -10,7 +10,6 @@ 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 {

View File

@ -0,0 +1,239 @@
//
// 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 dont 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
}
}

View File

@ -0,0 +1,41 @@
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

View File

@ -0,0 +1,23 @@
//
// 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
}
}
}

View File

@ -11,7 +11,6 @@ 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 {

View File

@ -10,7 +10,6 @@ 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 {
//-------------------------------------------------- //--------------------------------------------------

View File

@ -0,0 +1,149 @@
//
// 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)
}
}

View File

@ -0,0 +1,67 @@
MM/DD/YYYY
----------------
- Initial Brand 3.0 handoff
12/17/2021
----------------
- Replaced focusring colors (previously interactive/onlight/ondark) with accessibility/onlight/ondark colors
- Updated focus border name (previously interactive.focusring.onlight) with focusring.onlight/ondark
12/31/2021
----------------
- Updated Hover and Active state trigger specs. If triggered by mouse, Active same as Hover. If not, Active same as Default.
03/01/2022
----------------
- Replaced Close Non-Scaling icon with VDS Icon.
- Removed “vector effect” from Anatomy.
- Removed “weight” from Configurations.
08/10/2022
----------------
- Updated default and inverted prop to light and dark surface.
- Noted that button is optional within anatomy
09/06/2022
----------------
- Updated Anatomy element names to remove the word “Modal” from text elements, updated Button to be Button Group,
and noted Button Group as optional across all visuals within Anatomy.
11/30/2022
----------------
- Added "(web only)" to any instance of "keyboard focus"
12/13/2022
----------------
- Replaced focus border pixel and style & spacing values with tokens.
04/24/2023
----------------
- Updated all instances of Close Button (VDS Icon) with VDS Button Icon (size small)
- Button Icon placed 8px from top/right edge
- Use the Ghost variant of Button Icon
- Added Button Icon props to Elements spec
10/17/2023
----------------
- Added component tokens table
- Applied component tokens to light, dark surface configurations
11/22/2023
----------------
- Updated tab/desk visuals to reflect new corner radius value - 12px
- Updated border radius value in Anatomy
11/27/2023
----------------
- Updated border radius” to “corner radius” in Anatomy
12/1/2023
----------------
- Applied palette tokens instead of hardcoded values where component tokens included an opacity
- Removed layer opacity annotation for instances where opacity is built into a component token
07/18/2024
----------------
- Added Scrollbar hit area with z-index specifications to the Behaviors page
- Decreased the height of the Grab zone to equal the height of the scrollbar thumb on the Behaviors page

View File

@ -0,0 +1,237 @@
//
// 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 {}
}
}

View File

@ -0,0 +1,123 @@
//
// 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)
])
}
}
}

View File

@ -0,0 +1,28 @@
//
// ModalLaunchable.swift
// VDS
//
// Created by Kanamarlapudi, Vasavi on 09/09/24.
//
import Foundation
import UIKit
public protocol ModalLaunchable {
func presentModal(surface: Surface, modalModel: Modal.ModalModel, presenter: UIView?)
}
extension ModalLaunchable {
public func presentModal(surface: Surface, modalModel: Modal.ModalModel, presenter: UIView? = nil) {
if let presenting = UIApplication.topViewController() {
let modalViewController = ModalDialogViewController(nibName: nil, bundle: nil).with {
$0.surface = surface
$0.modalModel = modalModel
$0.presenter = presenter
$0.modalPresentationStyle = UIDevice.isIPad && !modalModel.fullScreenDialog ? .overCurrentContext : .fullScreen
$0.modalTransitionStyle = .crossDissolve
}
presenting.present(modalViewController, animated: true)
}
}
}

View File

@ -0,0 +1,45 @@
//
// ModalModel.swift
// VDS
//
// Created by Kanamarlapudi, Vasavi on 09/09/24.
//
import Foundation
import UIKit
extension Modal {
/// Model used to represent the modal.
public struct ModalModel: Equatable {
/// Current Surface and this is used to pass down to child objects that implement Surfacable
public var closeButtonText: String
public var title: String?
public var content: String?
public var contentView: UIView?
public var accessibleText: String?
public var contentViewAlignment: UIStackView.Alignment?
public var buttonData: [ButtonBase]?
public var fullScreenDialog: Bool
public var hideCloseButton: Bool
public init(closeButtonText: String = "Close",
title: String? = nil,
content: String? = nil,
contentView: UIView? = nil,
buttonData: [ButtonBase]? = nil,
fullScreenDialog: Bool = false,
hideCloseButton: Bool = false,
accessibleText: String? = "Modal",
contentViewAlignment: UIStackView.Alignment = .leading) {
self.closeButtonText = closeButtonText
self.title = title
self.content = content
self.contentView = contentView
self.accessibleText = accessibleText
self.contentViewAlignment = contentViewAlignment
self.buttonData = buttonData
self.fullScreenDialog = fullScreenDialog
self.hideCloseButton = hideCloseButton
}
}
}

View File

@ -14,7 +14,6 @@ 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 {

View File

@ -11,7 +11,6 @@ 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 {

View File

@ -9,7 +9,6 @@ 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 {
//-------------------------------------------------- //--------------------------------------------------

View File

@ -9,7 +9,6 @@ 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 {
@ -140,6 +139,7 @@ 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,6 +217,24 @@ 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

View File

@ -11,7 +11,6 @@ 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 {

View File

@ -12,7 +12,6 @@ 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 {

View File

@ -13,7 +13,6 @@ 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 {

View File

@ -11,7 +11,6 @@ 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 {

View File

@ -11,7 +11,6 @@ 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> {

View File

@ -10,7 +10,6 @@ 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 {
@ -27,7 +26,6 @@ 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
} }
@ -148,6 +146,7 @@ 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
} }
@ -162,4 +161,38 @@ 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
}
} }

View File

@ -45,6 +45,7 @@ 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()

View File

@ -11,8 +11,7 @@ import VDSCoreTokens
import Combine import Combine
extension Tabs { extension Tabs {
@objcMembers @objc(VDSTab)
@objc(VDSTab)
open class Tab: Control, Groupable { open class Tab: Control, Groupable {
//-------------------------------------------------- //--------------------------------------------------

View File

@ -10,7 +10,6 @@ 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 doesnt 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 doesnt need to be compared.
@objcMembers
@objc(VDSTabs) @objc(VDSTabs)
open class Tabs: View, ParentViewProtocol { open class Tabs: View, ParentViewProtocol {

View File

@ -8,7 +8,6 @@
import Foundation import Foundation
import UIKit import UIKit
@objcMembers
@objc(VDSTabsContainer) @objc(VDSTabsContainer)
open class TabsContainer: View { open class TabsContainer: View {

View File

@ -105,14 +105,12 @@ 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 { frame.size.width } internal var maxWidth: CGFloat { constrainedWidth }
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) }
@ -258,15 +256,9 @@ open class EntryFieldBase<ValueType>: Control, Changeable, FormFieldInternalVali
let layoutGuide = UILayoutGuide() let layoutGuide = UILayoutGuide()
addLayoutGuide(layoutGuide) addLayoutGuide(layoutGuide)
layoutGuide layoutGuide.pinToSuperView()
.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
@ -552,15 +544,10 @@ 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()
} }
} }

View File

@ -13,7 +13,6 @@ 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> {
@ -47,8 +46,9 @@ 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 = frame.size.width let frameWidth = constrainedWidth
return helperTextPlacement == .right ? (frameWidth - horizontalStackView.spacing) / 2 : frameWidth let halfWidth = (frameWidth - horizontalStackView.spacing) / 2
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,15 +320,12 @@ 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()
} }

View File

@ -10,7 +10,6 @@ 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 {

View File

@ -12,7 +12,6 @@ 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 thats longer than a single line. /// Use a text area when you want customers to enter text thats longer than a single line.
@objcMembers
@objc(VDSTextArea) @objc(VDSTextArea)
open class TextArea: EntryFieldBase<String> { open class TextArea: EntryFieldBase<String> {
//-------------------------------------------------- //--------------------------------------------------

View File

@ -10,7 +10,6 @@ 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 {

View File

@ -10,7 +10,6 @@ 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> {
@ -346,8 +345,15 @@ 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
items.append(contentsOf: elements) if containerView.isAccessibilityElement {
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 {}
@ -447,33 +453,6 @@ 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
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -499,6 +478,14 @@ 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 {
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -520,12 +507,6 @@ 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 {

View File

@ -15,7 +15,6 @@ 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 {
@ -29,9 +28,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.space3X : VDSLayout.space4X return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space3X
case .large: case .large:
return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space6X return UIDevice.isIPad ? VDSLayout.space6X : VDSLayout.space4X
} }
} }
@ -104,7 +103,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
} }
private var backgroundColorSurface: Surface { private var backgroundColorSurface: Surface {
backgroundColorConfiguration.getColor(self).surface backgroundColorConfiguration.getColor(self).isDark() ? .dark : .light
} }
//-------------------------------------------------- //--------------------------------------------------
@ -280,6 +279,7 @@ 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()
.pinTop() .pinTopGreaterThanOrEqualTo()
.pinBottom() .pinBottom()
directionalIcon directionalIcon
.pinTrailing() .pinTrailing()
.pinTop() .pinTopGreaterThanOrEqualTo()
.pinBottom() .pinBottom()
badge.bottomAnchor.constraint(equalTo: badge.label.bottomAnchor, constant: 2).activate() badge.bottomAnchor.constraint(equalTo: badge.label.bottomAnchor, constant: 2).activate()
@ -468,6 +468,7 @@ 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
@ -558,6 +559,7 @@ 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
} }
@ -568,6 +570,7 @@ 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
} }
@ -598,7 +601,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
} }
private func updateTextPositionAlignment() { private func updateTextPositionAlignment() {
guard width != nil && (aspectRatio != .none || height != nil) else { return } guard aspectRatio != .none || height != nil else { return }
switch textPostion { switch textPostion {
case .top: case .top:
titleLockupTopConstraint?.activate() titleLockupTopConstraint?.activate()

View File

@ -15,6 +15,9 @@ 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
@ -30,8 +33,9 @@ extension Tilelet {
/// LineBreakMode used in Badge label. /// LineBreakMode used in Badge label.
public var lineBreakMode: NSLineBreakMode public var lineBreakMode: NSLineBreakMode
public init(text: String, fillColor: Badge.FillColor = .red, surface: Surface = .light, numberOfLines: Int = 0, maxWidth: CGFloat? = nil, lineBreakMode: NSLineBreakMode = .byTruncatingTail) { public init(text: String, textColor: Badge.TextColor? = nil, 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

View File

@ -12,7 +12,6 @@ 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 {

View File

@ -12,7 +12,6 @@ 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 {
@ -208,8 +207,8 @@ open class Toggle: Control, Changeable, FormFieldable, ParentViewProtocol {
//toggle //toggle
toggleConstraints = [ toggleConstraints = [
toggleView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor), toggleView.leadingAnchor.constraint(equalTo: leadingAnchor),
toggleView.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor) toggleView.trailingAnchor.constraint(equalTo: trailingAnchor)
] ]
//toggle and label variants //toggle and label variants

View File

@ -12,7 +12,6 @@ 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 {

View File

@ -13,7 +13,6 @@ 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 {

View File

@ -10,7 +10,6 @@ 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 {

View File

@ -9,7 +9,6 @@ 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 {

View File

@ -187,10 +187,4 @@ 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
}
} }

View File

@ -192,4 +192,14 @@ 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
}
} }

View File

@ -647,7 +647,14 @@ 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 }

View File

@ -1,3 +1,26 @@
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

View File

@ -11,209 +11,72 @@ 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 let boldFeatureXLarge = TextStyle(rawValue: "boldFeatureXLarge", public static var allCases: [TextStyle] { Style.allCases.compactMap { Provider.style(for: $0) } }
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) return TextStyle(rawValue: "Custom\(font.fontName)", fontFace: .custom(font), pointSize: font.pointSize, lineHeight: min(font.lineHeight, font.pointSize))
} }
return found return found
} }

View File

@ -0,0 +1,246 @@
//
// 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")
}
}
}
}

View File

@ -32,12 +32,16 @@ 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``