Compare commits

...

106 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
Matt Bruce
2365f8dbf4 updated version
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-27 14:57:20 -05:00
Matt Bruce
296703076e updated from Control to View and add publisher
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-27 14:28:51 -05:00
Matt Bruce
c76d3e7b76 updated Pagination to a Control
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-27 14:04:41 -05:00
Matt Bruce
35036ca804 more updates on carousel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-27 13:31:48 -05:00
Matt Bruce
ad6291af30 force component to redraw
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-27 11:56:19 -05:00
Matt Bruce
31f01773c4 added borders to the cells for carousel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-27 11:44:10 -05:00
Matt Bruce
63499838c6 Merge branch 'develop' into mbruce/bugfix 2024-08-27 11:43:48 -05:00
Bruce, Matt R
e4630b65ea Merge branch 'bugfix/carousel' into 'develop'
refactoring Carousel to use a UICollectionView

See merge request BPHV_MIPS/vds_ios!297
2024-08-27 15:01:44 +00:00
Bruce, Matt R
47747c801e Merge branch 'bugfix/carouselPaginationCaret' into 'develop'
Pagination caret size and horizontal offset

See merge request BPHV_MIPS/vds_ios!296
2024-08-27 14:09:20 +00:00
Vasavi Kanamarlapudi
1f2637ed04 refactoring Carousel to use a UICollectionView 2024-08-27 11:54:41 +05:30
Matt Bruce
343f674251 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios.git into mbruce/bugfix 2024-08-23 09:04:59 -05:00
Vasavi Kanamarlapudi
9cbfe1d46a Digital ACT-191 ONEAPP-10586 story: added public properties 2024-08-22 17:08:12 +05:30
Matt Bruce
f2c6eb0fc2 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios.git into mbruce/bugfix 2024-08-21 15:32:53 -05:00
Matt Bruce
7536774c0f fixed bug in checkbox getting crushed.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 15:32:20 -05:00
Vasavi Kanamarlapudi
7667908ffd Digital ACT-191 ONEAPP-10586 story: added new file for footnote 2024-08-21 18:32:40 +05:30
Vasavi Kanamarlapudi
030ebdf897 added release note 2024-08-21 13:42:48 +05:30
Vasavi Kanamarlapudi
592d2c1f1f Digital ACT-191 CXTDT-603719 defect: Added fix for pagination caret icon 2024-08-21 13:39:35 +05:30
82 changed files with 2339 additions and 479 deletions

View File

@ -10,15 +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 */; };
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 */; };
@ -26,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 */; };
@ -59,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 */; };
@ -215,7 +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>"; };
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>"; };
@ -223,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>"; };
@ -236,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>"; };
@ -250,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>"; };
@ -278,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>"; };
@ -484,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 = (
@ -494,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 = (
@ -524,6 +573,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
18AE874F2C06FDA60075F181 /* Carousel.swift */, 18AE874F2C06FDA60075F181 /* Carousel.swift */,
183B16F22C78CF7C00BA6A10 /* CarouselSlotCell.swift */,
18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */, 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */,
18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */, 18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */,
18AE87532C06FE610075F181 /* CarouselChangeLog.txt */, 18AE87532C06FE610075F181 /* CarouselChangeLog.txt */,
@ -531,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 = (
@ -706,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 */,
@ -794,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>";
@ -912,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>";
@ -967,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>";
@ -1212,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 */,
); );
@ -1276,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 */,
@ -1292,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 */,
@ -1302,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 */,
@ -1318,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 */,
@ -1347,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 */,
@ -1355,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 */,
@ -1369,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 */,
@ -1383,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 */,
@ -1400,6 +1479,7 @@
EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */, EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */,
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */, EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */, EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */,
183B16F32C78CF7C00BA6A10 /* CarouselSlotCell.swift in Sources */,
44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */, 44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */,
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */, EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */, 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */,
@ -1419,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 */,
@ -1427,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 */,
@ -1589,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 = 72; CURRENT_PROJECT_VERSION = 75;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
@ -1627,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 = 72; 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 {
@ -87,9 +86,6 @@ open class SelectorBase: Control, SelectorControlable, ParentViewProtocol {
open var selectorColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() } } open var selectorColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() } }
/// The natural size for the receiving view, considering only properties of the view itself.
open override var intrinsicContentSize: CGSize { size }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
@ -109,6 +105,16 @@ open class SelectorBase: Control, SelectorControlable, ParentViewProtocol {
super.setup() super.setup()
isAccessibilityElement = true isAccessibilityElement = true
accessibilityTraits = .button accessibilityTraits = .button
let layoutGuide = UILayoutGuide()
addLayoutGuide(layoutGuide)
layoutGuide
.pinTop(0)
.pinLeading(0)
.pinTrailing(0, .defaultHigh)
.pinBottom(0, .defaultHigh)
.width(size.width)
.height(size.height)
} }
open override func setDefaults() { open override func setDefaults() {

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)
mainStackView.isUserInteractionEnabled = false //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.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
}
} }
//-------------------------------------------------- //--------------------------------------------------
@ -61,10 +68,12 @@ open class Badge: View, ParentViewProtocol {
/// This will render the badges fill color based on the available options. /// This will render the badges fill color based on the available options.
/// When used in conjunction with the surface prop, this fill color will change its tint automatically based on a light or dark surface. /// When used in conjunction with the surface prop, this fill color will change its tint automatically based on a light or dark surface.
open var fillColor: FillColor = .red { didSet { setNeedsUpdate() }} open var fillColor: FillColor = .red { didSet { setNeedsUpdate() }}
/// 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 {
case .red, .black: textColorConfiguration = configuration
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false) } else {
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true) if color.isDark() {
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
case .yellow, .white: textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true)
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false) } else {
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true) 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) }
}
if let textColor {
switch textColor {
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 .red, .black:
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
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 {
@ -154,27 +153,38 @@ open class Carousel: View {
$0.backgroundColor = .clear $0.backgroundColor = .clear
} }
private var scrollView = UIScrollView().with { private lazy var collectionView: UICollectionView = {
$0.translatesAutoresizingMaskIntoConstraints = false let layout = UICollectionViewFlowLayout()
$0.backgroundColor = .clear layout.scrollDirection = .horizontal
} let collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
collectionView.isScrollEnabled = true
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.delegate = self
collectionView.dataSource = self
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
collectionView.backgroundColor = .clear
collectionView.register(CarouselSlotCell.self,
forCellWithReuseIdentifier: CarouselSlotCell.identifier)
return collectionView
}()
/// Previous button to show previous slide. /// Previous button to show previous slide.
private var previousButton = ButtonIcon().with { private var previousButton = ButtonIcon().with {
$0.kind = .lowContrast $0.kind = .lowContrast
$0.iconName = .leftCaret $0.iconName = .paginationLeftCaret
$0.iconOffset = .init(x: -2, y: 0) $0.iconOffset = .init(x: -2, y: 0)
$0.customContainerSize = UIDevice.isIPad ? 40 : 28 $0.customContainerSize = UIDevice.isIPad ? 40 : 28
$0.icon.customSize = UIDevice.isIPad ? 16 : 12 $0.customIconSize = UIDevice.isIPad ? 16 : 12
} }
/// Next button to show next slide. /// Next button to show next slide.
private var nextButton = ButtonIcon().with { private var nextButton = ButtonIcon().with {
$0.kind = .lowContrast $0.kind = .lowContrast
$0.iconName = .rightCaret $0.iconName = .paginationRightCaret
$0.iconOffset = .init(x: 2, y: 0) $0.iconOffset = .init(x: 2, y: 0)
$0.customContainerSize = UIDevice.isIPad ? 40 : 28 $0.customContainerSize = UIDevice.isIPad ? 40 : 28
$0.icon.customSize = UIDevice.isIPad ? 16 : 12 $0.customIconSize = UIDevice.isIPad ? 16 : 12
} }
/// A publisher for when moving the carousel. Passes parameters selectedGroupIndex (position). /// A publisher for when moving the carousel. Passes parameters selectedGroupIndex (position).
@ -215,9 +225,9 @@ open class Carousel: View {
containerView.addSubview(contentStackView) containerView.addSubview(contentStackView)
// Add scrollview // Add scrollview
scrollContainerView.addSubview(scrollView) scrollContainerView.addSubview(collectionView)
scrollView.pinToSuperView() collectionView.pinToSuperView()
// Add pagination button icons // Add pagination button icons
scrollContainerView.addSubview(previousButton) scrollContainerView.addSubview(previousButton)
previousButton previousButton
@ -259,14 +269,25 @@ open class Carousel: View {
/// Used to make changes to the View based off a change events or from local properties. /// Used to make changes to the View based off a change events or from local properties.
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
updateScrollbar()
updateCarousel()
collectionView.collectionViewLayout.invalidateLayout()
collectionView.reloadData()
}
//--------------------------------------------------
// MARK: - Private Methods
//--------------------------------------------------
private func updateScrollbar() {
carouselScrollBar.numberOfSlides = views.count carouselScrollBar.numberOfSlides = views.count
carouselScrollBar.layout = layout carouselScrollBar.layout = layout
if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) { if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) {
carouselScrollBar.position = 1 carouselScrollBar.position = 1
} }
carouselScrollBar.isHidden = (totalPositions() <= 1) ? true : false carouselScrollBar.isHidden = (totalPositions() <= 1) ? true : false
}
private func updateCarousel() {
// Mobile/Tablet layouts without peek - must show pagination controls. // Mobile/Tablet layouts without peek - must show pagination controls.
// If peek is none, pagination controls should show. So set to persistent. // If peek is none, pagination controls should show. So set to persistent.
if peek == .none { if peek == .none {
@ -284,12 +305,9 @@ open class Carousel: View {
} }
updatePaginationControls() updatePaginationControls()
addCarouselSlots() updateContainerHeight()
} }
//--------------------------------------------------
// MARK: - Private Methods
//--------------------------------------------------
private func addlisteners() { private func addlisteners() {
nextButton.onClick = { _ in self.nextButtonClick() } nextButton.onClick = { _ in self.nextButtonClick() }
previousButton.onClick = { _ in self.previousButtonClick() } previousButton.onClick = { _ in self.previousButtonClick() }
@ -365,47 +383,13 @@ open class Carousel: View {
return height return height
} }
// Add carousel slots and load data if any // update carousel size and load data if any
private func addCarouselSlots() { private func updateContainerHeight() {
getSlotWidth() getSlotWidth()
if containerView.frame.size.width > 0 { if containerView.frame.size.width > 0 {
containerViewHeightConstraint?.isActive = false containerViewHeightConstraint?.isActive = false
containerStackHeightConstraint?.isActive = false containerStackHeightConstraint?.isActive = false
let slotHeight = fetchCarouselHeight() let slotHeight = fetchCarouselHeight()
// Perform a loop to iterate each subView
scrollView.subviews.forEach { subView in
// Removing subView from its parent view
subView.removeFromSuperview()
}
// Add carousel items
if views.count > 0 {
var xPos = 0.0
for index in 0...views.count - 1 {
// Add Carousel Slot
let carouselSlot = View().with {
$0.clipsToBounds = true
}
scrollView.addSubview(carouselSlot)
scrollView.delegate = self
carouselSlot
.pinTop()
.pinBottom()
.pinLeading(xPos)
.width(minimumSlotWidth)
.height(slotHeight)
xPos = xPos + minimumSlotWidth + gutter.value
let component = views[index]
carouselSlot.addSubview(component)
setSlotAlignment(contentView: component)
}
scrollView.contentSize = CGSize(width: xPos - gutter.value, height: slotHeight)
}
let containerHeight = slotHeight + scrollbarTopSpace + containerSize.height let containerHeight = slotHeight + scrollbarTopSpace + containerSize.height
if carouselScrollBar.isHidden { if carouselScrollBar.isHidden {
containerStackHeightConstraint = contentStackView.heightAnchor.constraint(equalToConstant: slotHeight) containerStackHeightConstraint = contentStackView.heightAnchor.constraint(equalToConstant: slotHeight)
@ -419,43 +403,6 @@ open class Carousel: View {
} }
} }
// Set slot alignment if provided. Used only when slot content have different heights or widths.
private func setSlotAlignment(contentView: UIView) {
switch slotAlignment?.vertical {
case .top:
contentView
.pinTop()
.pinBottomLessThanOrEqualTo()
case .middle:
contentView
.pinTopGreaterThanOrEqualTo()
.pinBottomLessThanOrEqualTo()
.pinCenterY()
case .bottom:
contentView
.pinTopGreaterThanOrEqualTo()
.pinBottom()
default: break
}
switch slotAlignment?.horizontal {
case .left:
contentView
.pinLeading()
.pinTrailingLessThanOrEqualTo()
case .center:
contentView
.pinLeadingGreaterThanOrEqualTo()
.pinTrailingLessThanOrEqualTo()
.pinCenterX()
case .right:
contentView
.pinLeadingGreaterThanOrEqualTo()
.pinTrailing()
default: break
}
}
// Get the slot width relative to the peak // Get the slot width relative to the peak
private func getSlotWidth() { private func getSlotWidth() {
let actualWidth = containerView.frame.size.width let actualWidth = containerView.frame.size.width
@ -505,7 +452,7 @@ open class Carousel: View {
} }
private func updateScrollbarPosition(targetContentOffsetXPos:CGFloat) { private func updateScrollbarPosition(targetContentOffsetXPos:CGFloat) {
let scrollContentSizeWidth = scrollView.contentSize.width let scrollContentSizeWidth = collectionView.contentSize.width
let totalPositions = totalPositions() let totalPositions = totalPositions()
let layoutSpace = Int (floor( Double(scrollContentSizeWidth / Double(totalPositions)))) let layoutSpace = Int (floor( Double(scrollContentSizeWidth / Double(totalPositions))))
let remindSpace = Int(targetContentOffsetXPos) % layoutSpace let remindSpace = Int(targetContentOffsetXPos) % layoutSpace
@ -515,10 +462,11 @@ open class Carousel: View {
updateScrollPosition(position: contentPos, callbackText: "ScrollViewMoved") updateScrollPosition(position: contentPos, callbackText: "ScrollViewMoved")
} }
// Update scrollview offset relative to scrollbar thumb position // Update collectionview offset relative to scrollbar thumb position
private func updateScrollPosition(position: Int, callbackText: String) { private func updateScrollPosition(position: Int, callbackText: String) {
if carouselScrollBar.numberOfSlides > 0 { if carouselScrollBar.numberOfSlides > 0 {
let scrollContentSizeWidth = scrollView.contentSize.width let scrollContentSizeWidth = collectionView.contentSize.width
let totalPositions = totalPositions() let totalPositions = totalPositions()
var xPos = 0.0 var xPos = 0.0
if position == 1 { if position == 1 {
@ -536,8 +484,8 @@ open class Carousel: View {
} }
} }
carouselScrollBar.scrubberId = position+1 carouselScrollBar.scrubberId = position+1
let yPos = scrollView.contentOffset.y let yPos = collectionView.contentOffset.y
scrollView.setContentOffset(CGPoint(x: xPos, y: yPos), animated: true) collectionView.setContentOffset(CGPoint(x: xPos, y: yPos), animated: true)
showPaginationControls() showPaginationControls()
groupIndex = position-1 groupIndex = position-1
onChangePublisher.send(groupIndex) onChangePublisher.send(groupIndex)
@ -557,5 +505,35 @@ extension Carousel: UIScrollViewDelegate {
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
updateScrollbarPosition(targetContentOffsetXPos: targetContentOffset.pointee.x) updateScrollbarPosition(targetContentOffsetXPos: targetContentOffset.pointee.x)
} }
}
extension Carousel: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
//--------------------------------------------------
// MARK: - UICollectionView Delegate & Datasource
//--------------------------------------------------
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
views.count
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CarouselSlotCell.identifier, for: indexPath) as? CarouselSlotCell else { return UICollectionViewCell() }
let component = views[indexPath.row]
cell.update(with: component, slotAlignment: slotAlignment, surface: surface)
cell.layoutIfNeeded()
//component.setNeedsLayout()
if hasDebugBorder {
cell.addDebugBorder()
} else {
cell.removeDebugBorder()
}
return cell
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return gutter.value
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: minimumSlotWidth, height: fetchCarouselHeight())
}
} }

View File

@ -0,0 +1,85 @@
//
// CarouselSlotCell.swift
// VDS
//
// Created by Kanamarlapudi, Vasavi on 23/08/24.
//
import Foundation
import UIKit
final class CarouselSlotCell: UICollectionViewCell {
///Identifier for the Calendar Date Cell.
static let identifier: String = String(describing: CarouselSlotCell.self)
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setUp()
}
//--------------------------------------------------
// MARK: - Private Methods
//--------------------------------------------------
/// Configuring the cell with default setup.
private func setUp() {
isAccessibilityElement = true
}
/// Updating UI based on data along with surface.
func update(with component: UIView, slotAlignment: Carousel.CarouselSlotAlignmentModel?, surface: Surface) {
contentView.subviews.forEach { $0.removeFromSuperview() }
contentView.addSubview(component)
if var surfacedView = component as? Surfaceable {
surfacedView.surface = surface
}
setSlotAlignment(alignment: slotAlignment, contentView: component)
}
// Set slot alignment if provided. Used only when slot content have different heights or widths.
private func setSlotAlignment(alignment: Carousel.CarouselSlotAlignmentModel?, contentView: UIView) {
switch alignment?.vertical {
case .top:
contentView
.pinTop()
.pinBottomLessThanOrEqualTo()
case .middle:
contentView
.pinTopGreaterThanOrEqualTo()
.pinBottomLessThanOrEqualTo()
.pinCenterY()
case .bottom:
contentView
.pinTopGreaterThanOrEqualTo()
.pinBottom()
default: break
}
switch alignment?.horizontal {
case .left:
contentView
.pinLeading()
.pinTrailingLessThanOrEqualTo()
case .center:
contentView
.pinLeadingGreaterThanOrEqualTo()
.pinTrailingLessThanOrEqualTo()
.pinCenterX()
case .right:
contentView
.pinLeadingGreaterThanOrEqualTo()
.pinTrailing()
default: break
}
}
}

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,9 +330,7 @@ open class InputStepper: EntryFieldBase<Int> {
stepperWidthConstraint?.deactivate() stepperWidthConstraint?.deactivate()
widthConstraint?.deactivate() widthConstraint?.deactivate()
trailingLessThanEqualsConstraint?.deactivate()
trailingEqualsConstraint?.deactivate()
var widthConstraintConstant: CGFloat? var widthConstraintConstant: CGFloat?
if let widthPercentage, let superWidth = horizontalPinnedWidth() { if let widthPercentage, let superWidth = horizontalPinnedWidth() {
@ -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,13 +11,14 @@ import VDSCoreTokens
import Combine import Combine
///Pagination is a control that enables customers to navigate multiple pages of content by selecting either a specific page or the next or previous set of four pages. ///Pagination is a control that enables customers to navigate multiple pages of content by selecting either a specific page or the next or previous set of four pages.
@objcMembers
@objc(VDSPagination) @objc(VDSPagination)
open class Pagination: View { open class Pagination: View {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
private let pageChangedSubject = PassthroughSubject<Pagination, Never>()
///Maximum component width ///Maximum component width
private let maxWidth: CGFloat = 288.0 private let maxWidth: CGFloat = 288.0
///Collectionview width anchor ///Collectionview width anchor
@ -52,6 +53,8 @@ open class Pagination: View {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Public Properties // MARK: - Public Properties
//-------------------------------------------------- //--------------------------------------------------
public var pageChangedPublisher: AnyPublisher<Pagination, Never> { pageChangedSubject.eraseToAnyPublisher() }
///Previous button to select previous page ///Previous button to select previous page
public let previousButton: PaginationButton = .init(type: .previous) public let previousButton: PaginationButton = .init(type: .previous)
///Next button to select next page ///Next button to select next page
@ -145,6 +148,11 @@ open class Pagination: View {
.sink { [weak self] value in .sink { [weak self] value in
self?.collectionViewWidthAnchor?.constant = value //As cell width is dynamic i.e cell may contain 2 or 3 or 4 charcters. Make sure that all the visible cells are displayed. self?.collectionViewWidthAnchor?.constant = value //As cell width is dynamic i.e cell may contain 2 or 3 or 4 charcters. Make sure that all the visible cells are displayed.
}.store(in: &subscribers) }.store(in: &subscribers)
pageChangedPublisher.sink { [weak self] control in
guard let self else { return }
onPageDidSelect?(control.selectedPage)
}.store(in: &subscribers)
} }
open override func setDefaults() { open override func setDefaults() {
@ -195,6 +203,7 @@ open class Pagination: View {
let isNextAction = sender == nextButton let isNextAction = sender == nextButton
_selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 } _selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 }
updateSelection() updateSelection()
pageChangedSubject.send(self)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
guard let self else { return } guard let self else { return }
UIAccessibility.post(notification: .announcement, argument: paginationDescription) UIAccessibility.post(notification: .announcement, argument: paginationDescription)
@ -249,7 +258,7 @@ extension Pagination: UICollectionViewDelegate, UICollectionViewDataSource, UICo
guard _selectedPageIndex != indexPath.row else { return } guard _selectedPageIndex != indexPath.row else { return }
_selectedPageIndex = indexPath.row _selectedPageIndex = indexPath.row
updateSelection() updateSelection()
onPageDidSelect?(selectedPage) pageChangedSubject.send(self)
} }
} }

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
@ -549,18 +541,13 @@ open class EntryFieldBase<ValueType>: Control, Changeable, FormFieldInternalVali
containerView.layer.borderWidth = VDSFormControls.borderWidth containerView.layer.borderWidth = VDSFormControls.borderWidth
containerView.layer.cornerRadius = VDSFormControls.borderRadius containerView.layer.cornerRadius = VDSFormControls.borderRadius
} }
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,8 +1,32 @@
1.0.76
----------------
- ONEAPP-11355 - ListUnordered - Finished Development
- CXTDT-630735 - PriceLockup - Accessibility
- CXTDT-626164 - FootnoteGroup - Dark mode
- CXTDT-626180 - FootnoteItem - Symbol type padding
- CXTDT-586383 - Table - Line style can be selected for each row.
1.0.75
----------------
- CXTDT-624895 - Badge - Custom FillColor and TextColor
- CXTDT-578885 - Table - Setting appropriate accessiblity label for each cell.
1.0.74
----------------
- CXTDT-591307 - DatePicker - Accessibility - #1 & #2
- CXTDT-577374 - Label - Spanish - Accent mark displays incorrectly
- CXTDT-595956 - Tilelet - Text Position does not work on Light surface
- CXTDT-595952 - Tilelet - Aspect Ratio Width/height setting
- CXTDT-595970 - Tilelet - Subtitle size options missing
- CXTDT-595965 - Tilelet - Incorrect Mobile Padding
- ONEAPP-10583 - Modal - Finished Development
1.0.73 1.0.73
---------------- ----------------
- CXTDT-597984 - Table - Text wrap - CXTDT-597984 - Table - Text wrap
- CXTDT-586372 - Table - Stripes defect - CXTDT-586372 - Table - Stripes defect
- CXTDT-586383 - Table - Line style - CXTDT-586383 - Table - Line style
- CXTDT-603719 - Carousel - Pagination caret icon
1.0.72 1.0.72
---------------- ----------------

View File

@ -11,209 +11,72 @@ import VDSCoreTokens
//MARK: Definitions //MARK: Definitions
extension TextStyle { extension TextStyle {
internal enum Style: String, CaseIterable {
// Static properties for different text styles case boldFeatureXLarge
case featureXLarge
public static let boldFeatureXLarge = TextStyle(rawValue: "boldFeatureXLarge", case boldFeatureLarge
fontFace: .edsBold, case featureLarge
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96, case boldFeatureMedium
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88, case featureMedium
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4)) case boldFeatureSmall
case featureSmall
public static let featureXLarge = TextStyle(rawValue: "featureXLarge", case boldFeatureXSmall
fontFace: .dsLight, case featureXSmall
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96, case boldTitle2XLarge
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88, case title2XLarge
letterSpacing: VDSTypography.letterSpacingSemiwide, case boldTitleXLarge
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4)) case titleXLarge
case boldTitleLarge
public static let boldFeatureLarge = TextStyle(rawValue: "boldFeatureLarge", case titleLarge
fontFace: .edsBold, case boldTitleMedium
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80, case titleMedium
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76, case boldTitleSmall
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2)) case titleSmall
case boldBodyLarge
public static let featureLarge = TextStyle(rawValue: "featureLarge", case bodyLarge
fontFace: .dsLight, case boldBodyMedium
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80, case bodyMedium
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76, case boldBodySmall
letterSpacing: VDSTypography.letterSpacingSemiwide, case bodySmall
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2)) case boldMicro
case micro
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
]
} }
// Static properties for different text styles
public static var boldFeatureXLarge: TextStyle { Provider.style(for: .boldFeatureXLarge) }
public static var featureXLarge: TextStyle { Provider.style(for: .featureXLarge) }
public static var boldFeatureLarge: TextStyle { Provider.style(for: .boldFeatureLarge) }
public static var featureLarge: TextStyle { Provider.style(for: .featureLarge) }
public static var boldFeatureMedium: TextStyle { Provider.style(for: .boldFeatureMedium) }
public static var featureMedium: TextStyle { Provider.style(for: .featureMedium) }
public static var boldFeatureSmall: TextStyle { Provider.style(for: .boldFeatureSmall) }
public static var featureSmall: TextStyle { Provider.style(for: .featureSmall) }
public static var boldFeatureXSmall: TextStyle { Provider.style(for: .boldFeatureXSmall) }
public static var featureXSmall: TextStyle { Provider.style(for: .featureXSmall) }
public static var boldTitle2XLarge: TextStyle { Provider.style(for: .boldTitle2XLarge) }
public static var title2XLarge: TextStyle { Provider.style(for: .title2XLarge) }
public static var boldTitleXLarge: TextStyle { Provider.style(for: .boldTitleXLarge) }
public static var titleXLarge: TextStyle { Provider.style(for: .titleXLarge) }
public static var boldTitleLarge: TextStyle { Provider.style(for: .boldTitleLarge) }
public static var titleLarge: TextStyle { Provider.style(for: .titleLarge) }
public static var boldTitleMedium: TextStyle { Provider.style(for: .boldTitleMedium) }
public static var titleMedium: TextStyle { Provider.style(for: .titleMedium) }
public static var boldTitleSmall: TextStyle { Provider.style(for: .boldTitleSmall) }
public static var titleSmall: TextStyle { Provider.style(for: .titleSmall) }
public static var boldBodyLarge: TextStyle { Provider.style(for: .boldBodyLarge) }
public static var bodyLarge: TextStyle { Provider.style(for: .bodyLarge) }
public static var boldBodyMedium: TextStyle { Provider.style(for: .boldBodyMedium) }
public static var bodyMedium: TextStyle { Provider.style(for: .bodyMedium) }
public static var boldBodySmall: TextStyle { Provider.style(for: .boldBodySmall) }
public static var bodySmall: TextStyle { Provider.style(for: .bodySmall) }
public static var boldMicro: TextStyle { Provider.style(for: .boldMicro) }
public static var micro: TextStyle { Provider.style(for: .micro) }
public static var allCases: [TextStyle] { Style.allCases.compactMap { Provider.style(for: $0) } }
public static 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``