@momo-kits/native-kits 0.162.30 → 0.162.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CLAUDE.md +19 -0
  2. package/ios/Application/ApplicationEnvironment.swift +14 -6
  3. package/ios/Application/LanguageSource.swift +93 -0
  4. package/ios/Application/Localize.swift +73 -4
  5. package/ios/Application/LocalizeModifier.swift +30 -0
  6. package/ios/Application/Navigation/NavigationContainer.swift +28 -18
  7. package/ios/Application/Navigation/Navigator.swift +121 -53
  8. package/ios/Application/Navigation/NavigatorManager.swift +49 -0
  9. package/ios/Application/Navigation/component/NavigationFooter.swift +90 -0
  10. package/ios/Application/StackScreen.swift +19 -28
  11. package/ios/Badge/Badge.swift +2 -1
  12. package/ios/Badge/BadgeRibbon.swift +6 -2
  13. package/ios/Button/Button.swift +41 -61
  14. package/ios/Chip/Chip.swift +6 -5
  15. package/ios/Icon/Icon.swift +13 -4
  16. package/ios/Input/ErrorView.swift +2 -1
  17. package/ios/Input/Input.swift +9 -2
  18. package/ios/Input/InputPhoneNumber.swift +2 -1
  19. package/ios/Input/InputSearch.swift +3 -2
  20. package/ios/Input/InputTextArea.swift +6 -1
  21. package/ios/InputMoney/InputMoney.swift +5 -2
  22. package/ios/InputOTP/InputOTP.swift +2 -1
  23. package/ios/Layout/GridContext.swift +30 -0
  24. package/ios/Layout/Item.swift +42 -0
  25. package/ios/Layout/Section.swift +134 -0
  26. package/ios/Popup/PopupNotify.swift +2 -1
  27. package/ios/ProgressInfo/ProgressInfo.swift +4 -3
  28. package/ios/Rating/Rating.swift +2 -1
  29. package/ios/Stepper/Stepper.swift +2 -1
  30. package/ios/SuggestAction/SuggestAction.swift +3 -2
  31. package/ios/Tag/Tag.swift +2 -1
  32. package/ios/Template/TrustBanner/TrustBanner.swift +4 -2
  33. package/ios/Title/Title.swift +3 -2
  34. package/ios/Tooltip/Tooltip.swift +2 -1
  35. package/ios/Typography/FontScale.swift +103 -0
  36. package/ios/Typography/FontScaleStore.swift +52 -13
  37. package/ios/Typography/Text.swift +12 -29
  38. package/ios/Typography/Typography.swift +66 -86
  39. package/ios/native-kits.podspec +2 -1
  40. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  41. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +87 -73
  42. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +55 -249
  43. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +90 -82
  44. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +74 -104
  45. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +47 -50
  46. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +63 -7
  47. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +90 -81
  48. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +73 -97
  49. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DemoScreen.swift +420 -0
  50. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +46 -4
  51. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +54 -57
  52. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +80 -45
  53. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconDemo.swift +81 -0
  54. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +49 -62
  55. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +66 -116
  56. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +104 -98
  57. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +76 -118
  58. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +73 -86
  59. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +69 -54
  60. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +74 -54
  61. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +73 -20
  62. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +68 -38
  63. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +55 -52
  64. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +51 -4
  65. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +14 -2
  66. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +47 -51
  67. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PlaygroundData.swift +76 -0
  68. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +67 -93
  69. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +34 -43
  70. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +83 -71
  71. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +55 -23
  72. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +58 -46
  73. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SectionDemo.swift +83 -0
  74. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +41 -12
  75. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +67 -127
  76. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +54 -110
  77. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +69 -79
  78. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +78 -58
  79. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +76 -65
  80. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +82 -127
  81. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +44 -19
  82. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +92 -168
  83. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +79 -27
  84. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +0 -1
  85. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +87 -92
  86. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +94 -163
  87. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +70 -70
  88. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +68 -114
  89. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +3 -1
  90. package/package.json +2 -2
@@ -1,152 +1,107 @@
1
+ //
2
+ // SwipeDemo.swift
3
+ // Example
4
+ //
5
+ // Preview + Playground demo, mirroring Compose's SwipeUsage.kt.
6
+ //
7
+
1
8
  import MoMoUIKits
2
9
  import SwiftUI
3
10
 
11
+ private func swipeContent(_ text: String) -> some View {
12
+ HStack {
13
+ MomoText(text, typography: .bodyDefaultRegular, color: Colors.text)
14
+ Spacer(minLength: 0)
15
+ }
16
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
17
+ .padding(.horizontal, Spacing.M)
18
+ .background(Colors.card)
19
+ }
20
+
4
21
  struct SwipeDemo: View {
5
- @State private var showLeftActions = true
6
- @State private var showRightActions = true
7
- @State private var heightValue: Double = 56
8
- @State private var radiusValue: Double = 0
9
- @State private var lastAction = "No action yet"
22
+ var body: some View {
23
+ if #available(iOS 16.0, *) {
24
+ DemoScreen(preview: { SwipePreview() }, playground: { SwipePlayground() })
25
+ } else {
26
+ Text("Requires iOS 16+").padding()
27
+ }
28
+ }
29
+ }
30
+
31
+ // MARK: - Preview
10
32
 
33
+ private struct SwipePreview: View {
11
34
  private var editAction: SwipeAction {
12
- SwipeAction(
13
- label: "Edit",
14
- icon: "24_basic_copy",
15
- backgroundColor: Colors.blue03,
16
- onPress: { lastAction = "Edit pressed" }
17
- )
35
+ SwipeAction(label: "Edit", icon: "24_basic_copy", backgroundColor: Colors.blue03, onPress: {})
18
36
  }
19
-
20
37
  private var deleteAction: SwipeAction {
21
- SwipeAction(
22
- label: "Delete",
23
- icon: "24_basic_delete",
24
- backgroundColor: Colors.red03,
25
- onPress: { lastAction = "Delete pressed" }
26
- )
38
+ SwipeAction(label: "Delete", icon: "24_basic_delete", backgroundColor: Colors.red03, onPress: {})
27
39
  }
28
-
29
40
  private var archiveAction: SwipeAction {
30
- SwipeAction(
31
- label: "Archive",
32
- icon: "24_basic_flag",
33
- backgroundColor: Colors.orange03,
34
- onPress: { lastAction = "Archive pressed" }
35
- )
41
+ SwipeAction(label: "Archive", icon: "24_basic_flag", backgroundColor: Colors.orange03, onPress: {})
36
42
  }
37
43
 
38
44
  var body: some View {
39
- ScrollView {
40
- VStack(alignment: .leading, spacing: Spacing.XL) {
41
- preview
42
- Divider()
43
- playground
44
- }
45
- .padding(.vertical, Spacing.L)
45
+ BasicColumnBox("Right actions only", alignment: .leading) {
46
+ Swipe(rightActions: [deleteAction]) { swipeContent("Swipe left to delete") }
46
47
  }
47
- .background(Colors.background)
48
- }
49
-
50
- private var preview: some View {
51
- VStack(alignment: .leading, spacing: Spacing.XL) {
52
- section("Right actions only") {
53
- Swipe(rightActions: [deleteAction]) {
54
- swipeContent("Swipe left to delete")
55
- }
56
- }
57
-
58
- section("Left actions only") {
59
- Swipe(leftActions: [editAction, archiveAction]) {
60
- swipeContent("Swipe right for actions")
61
- }
62
- }
63
-
64
- section("Both sides") {
65
- Swipe(leftActions: [editAction], rightActions: [deleteAction]) {
66
- swipeContent("Swipe both directions")
67
- }
68
- }
69
-
70
- section("Multiple right actions") {
71
- Swipe(rightActions: [editAction, archiveAction, deleteAction]) {
72
- swipeContent("3 right actions")
73
- }
74
- }
75
-
76
- section("With itemRadius") {
77
- Swipe(rightActions: [deleteAction], itemRadius: Radius.S) {
78
- swipeContent("Rounded corners")
79
- }
80
- }
81
-
82
- section("Custom height") {
83
- Swipe(rightActions: [deleteAction], height: 80) {
84
- swipeContent("Taller row (80dp)")
85
- }
86
- }
48
+ BasicColumnBox("Left actions only", alignment: .leading) {
49
+ Swipe(leftActions: [editAction, archiveAction]) { swipeContent("Swipe right for actions") }
50
+ }
51
+ BasicColumnBox("Both sides", alignment: .leading) {
52
+ Swipe(leftActions: [editAction], rightActions: [deleteAction]) { swipeContent("Swipe both directions") }
53
+ }
54
+ BasicColumnBox("Multiple right actions", alignment: .leading) {
55
+ Swipe(rightActions: [editAction, archiveAction, deleteAction]) { swipeContent("3 right actions") }
56
+ }
57
+ BasicColumnBox("With itemRadius", alignment: .leading) {
58
+ Swipe(rightActions: [deleteAction], itemRadius: Radius.S) { swipeContent("Rounded corners") }
59
+ }
60
+ BasicColumnBox("Custom height", alignment: .leading) {
61
+ Swipe(rightActions: [deleteAction], height: 80) { swipeContent("Taller row (80dp)") }
87
62
  }
88
63
  }
64
+ }
89
65
 
90
- private var playground: some View {
91
- section("Playground") {
92
- Toggle(isOn: $showLeftActions) {
93
- MomoText("Show Left Actions", typography: .labelSMedium, color: Colors.text)
94
- }
95
-
96
- Toggle(isOn: $showRightActions) {
97
- MomoText("Show Right Actions", typography: .labelSMedium, color: Colors.text)
98
- }
99
-
100
- VStack(alignment: .leading, spacing: Spacing.XS) {
101
- MomoText("Height: \(Int(heightValue))", typography: .labelSMedium, color: Colors.textSecondary)
102
- Slider(value: $heightValue, in: 40...100, step: 1)
103
- }
104
-
105
- VStack(alignment: .leading, spacing: Spacing.XS) {
106
- MomoText("Item Radius: \(Int(radiusValue))", typography: .labelSMedium, color: Colors.textSecondary)
107
- Slider(value: $radiusValue, in: 0...24, step: 1)
108
- }
66
+ // MARK: - Playground
109
67
 
110
- Swipe(
111
- leftActions: showLeftActions ? [editAction, archiveAction] : [],
112
- rightActions: showRightActions ? [deleteAction] : [],
113
- height: CGFloat(heightValue),
114
- itemRadius: CGFloat(radiusValue)
115
- ) {
116
- swipeContent("Swipe me!")
117
- }
68
+ @available(iOS 16.0, *)
69
+ private struct SwipePlayground: View {
70
+ @State private var showLeftActions = true
71
+ @State private var showRightActions = true
72
+ @State private var heightValue: Double = 56
73
+ @State private var radiusValue: Double = 0
74
+ @State private var lastAction = "No action yet"
118
75
 
119
- MomoText(lastAction, typography: .descriptionDefaultRegular, color: Colors.textSecondary)
120
- }
76
+ private var editAction: SwipeAction {
77
+ SwipeAction(label: "Edit", icon: "24_basic_copy", backgroundColor: Colors.blue03, onPress: { lastAction = "Edit pressed" })
121
78
  }
122
-
123
- @ViewBuilder
124
- private func section<Content: View>(
125
- _ title: String,
126
- @ViewBuilder content: () -> Content
127
- ) -> some View {
128
- VStack(alignment: .leading, spacing: Spacing.M) {
129
- MomoText(title, typography: .headerSSemibold, color: Colors.text)
130
- content()
131
- }
132
- .padding(.horizontal, Spacing.M)
79
+ private var deleteAction: SwipeAction {
80
+ SwipeAction(label: "Delete", icon: "24_basic_delete", backgroundColor: Colors.red03, onPress: { lastAction = "Delete pressed" })
133
81
  }
134
-
135
- private func swipeContent(_ text: String) -> some View {
136
- HStack {
137
- MomoText(text, typography: .bodyDefaultRegular, color: Colors.text)
138
- Spacer(minLength: 0)
139
- }
140
- .frame(maxWidth: .infinity, maxHeight: .infinity)
141
- .padding(.horizontal, Spacing.M)
142
- .background(Colors.card)
82
+ private var archiveAction: SwipeAction {
83
+ SwipeAction(label: "Archive", icon: "24_basic_flag", backgroundColor: Colors.orange03, onPress: { lastAction = "Archive pressed" })
143
84
  }
144
- }
145
85
 
146
- #if DEBUG
147
- struct SwipeDemo_Previews: PreviewProvider {
148
- static var previews: some View {
149
- SwipeDemo()
86
+ var body: some View {
87
+ PlaygroundTab(
88
+ component: {
89
+ VStack(alignment: .leading, spacing: Spacing.S) {
90
+ Swipe(
91
+ leftActions: showLeftActions ? [editAction, archiveAction] : [],
92
+ rightActions: showRightActions ? [deleteAction] : [],
93
+ height: CGFloat(heightValue),
94
+ itemRadius: CGFloat(radiusValue)
95
+ ) { swipeContent("Swipe me!") }
96
+ MomoText(lastAction, typography: .descriptionDefaultRegular, color: Colors.textSecondary)
97
+ }
98
+ },
99
+ params: [
100
+ .checkbox("ShowLeftActions", $showLeftActions),
101
+ .checkbox("ShowRightActions", $showRightActions),
102
+ .slider("Height", $heightValue, min: 40, max: 100, step: 1),
103
+ .slider("ItemRadius", $radiusValue, min: 0, max: 24, step: 1),
104
+ ]
105
+ )
150
106
  }
151
107
  }
152
- #endif
@@ -2,32 +2,57 @@
2
2
  // SwitchDemo.swift
3
3
  // Example
4
4
  //
5
- // Created by dung.pham2 on 3/12/24.
5
+ // Preview + Playground demo for Switch.
6
6
  //
7
7
 
8
- import SwiftUI
9
8
  import MoMoUIKits
9
+ import SwiftUI
10
10
 
11
11
  struct SwitchDemo: View {
12
+ var body: some View {
13
+ if #available(iOS 16.0, *) {
14
+ DemoScreen(preview: { SwitchPreview() }, playground: { SwitchPlayground() })
15
+ } else {
16
+ Text("Requires iOS 16+").padding()
17
+ }
18
+ }
19
+ }
20
+
21
+ // MARK: - Preview
22
+
23
+ private struct SwitchPreview: View {
12
24
  @State private var checked = false
13
-
25
+
14
26
  var body: some View {
15
- VStack(alignment: .leading, spacing: 8) {
16
- Text("Value")
17
- Switch($checked, onChange: { newValue in
18
- checked = newValue
19
- })
20
-
21
-
22
- Text("Disabled")
23
- Switch( .constant(true), disabled: true, onChange: { _ in
24
- checked = !checked
25
- })
26
-
27
- Switch( .constant(false), disabled: true, onChange: { _ in
28
- checked = !checked
29
- })
27
+ BasicColumnBox("Value", alignment: .leading) {
28
+ Switch($checked, onChange: { checked = $0 })
30
29
  }
31
- .padding()
30
+ BasicColumnBox("Disabled (on)", alignment: .leading) {
31
+ Switch(.constant(true), disabled: true)
32
+ }
33
+ BasicColumnBox("Disabled (off)", alignment: .leading) {
34
+ Switch(.constant(false), disabled: true)
35
+ }
36
+ }
37
+ }
38
+
39
+ // MARK: - Playground
40
+
41
+ @available(iOS 16.0, *)
42
+ private struct SwitchPlayground: View {
43
+ @State private var value = false
44
+ @State private var title = ""
45
+ @State private var disabled = false
46
+
47
+ var body: some View {
48
+ PlaygroundTab(
49
+ component: {
50
+ Switch($value, disabled: disabled, onChange: { value = $0 }, title: title)
51
+ },
52
+ params: [
53
+ .string("Title", $title),
54
+ .checkbox("Disabled", $disabled),
55
+ ]
56
+ )
32
57
  }
33
58
  }
@@ -2,189 +2,113 @@
2
2
  // TabViewDemo.swift
3
3
  // Example
4
4
  //
5
+ // Preview + Playground demo, mirroring Compose's TabViewUsage.kt.
6
+ //
5
7
 
6
- import Foundation
7
8
  import MoMoUIKits
8
9
  import SwiftUI
9
10
 
10
- // MARK: - TabViewDemo
11
-
12
- struct TabViewDemo: View {
13
- var body: some View {
14
- ScrollView {
15
- VStack(alignment: .leading, spacing: 24) {
16
- section("Default (2 tabs)") {
17
- MomoTabView(
18
- tabs: [
19
- TabViewItem(title: "Tab 1") { tabContent("Content 1", Colors.pink09) },
20
- TabViewItem(title: "Tab 2") { tabContent("Content 2", Colors.blue08) },
21
- ]
22
- )
23
- .frame(height: 160)
24
- }
25
-
26
- section("Default (3 tabs)") {
27
- MomoTabView(
28
- tabs: [
29
- TabViewItem(title: "Overview") { tabContent("Overview", Colors.pink09) },
30
- TabViewItem(title: "Activity") { tabContent("Activity", Colors.blue08) },
31
- TabViewItem(title: "Settings") { tabContent("Settings", Colors.green08) },
32
- ]
33
- )
34
- .frame(height: 160)
35
- }
36
-
37
- section("With badge & dot") {
38
- MomoTabView(
39
- tabs: [
40
- TabViewItem(title: "Inbox", badgeValue: "5") { tabContent("Inbox", Colors.orange08) },
41
- TabViewItem(title: "Alerts", showDot: true, dotSize: .small) { tabContent("Alerts", Colors.red08) },
42
- TabViewItem(title: "Done") { tabContent("Done", Colors.green08) },
43
- ]
44
- )
45
- .frame(height: 160)
46
- }
47
-
48
- section("Scrollable (many tabs)") {
49
- MomoTabView(
50
- tabs: [
51
- TabViewItem(title: "Monday") { tabContent("Monday", Colors.pink09) },
52
- TabViewItem(title: "Tuesday") { tabContent("Tuesday", Colors.blue08) },
53
- TabViewItem(title: "Wednesday") { tabContent("Wednesday", Colors.green08) },
54
- TabViewItem(title: "Thursday") { tabContent("Thursday", Colors.orange08) },
55
- TabViewItem(title: "Friday") { tabContent("Friday", Colors.mint08) },
56
- TabViewItem(title: "Saturday") { tabContent("Saturday", Colors.red08) },
57
- TabViewItem(title: "Sunday") { tabContent("Sunday", Colors.pink09) },
58
- ],
59
- scrollable: true,
60
- selectedColor: Colors.pink01,
61
- unselectedColor: Colors.blue07
62
- )
63
- .frame(height: 160)
64
- }
65
-
66
- section("Card type") {
67
- MomoTabView(
68
- tabs: [
69
- TabViewItem(title: "Personal") { tabContent("Personal", Colors.pink09) },
70
- TabViewItem(title: "Business") { tabContent("Business", Colors.blue08) },
71
- TabViewItem(title: "Savings") { tabContent("Savings", Colors.green08) },
72
- ],
73
- type: .card
74
- )
75
- .frame(height: 160)
76
- }
77
-
78
- section("Card type with icon") {
79
- MomoTabView(
80
- tabs: [
81
- TabViewItem(title: "Home", icon: "basic_home") { tabContent("Home", Colors.pink09) },
82
- TabViewItem(title: "Search", icon: "basic_search") { tabContent("Search", Colors.blue08) },
83
- ],
84
- type: .card
85
- )
86
- .frame(height: 160)
87
- }
88
-
89
- section("Column direction") {
90
- MomoTabView(
91
- tabs: [
92
- TabViewItem(title: "Home", icon: "basic_home") { tabContent("Home", Colors.pink09) },
93
- TabViewItem(title: "Search", icon: "basic_search") { tabContent("Search", Colors.blue08) },
94
- TabViewItem(title: "Profile", icon: "basic_user") { tabContent("Profile", Colors.green08) },
95
- ],
96
- direction: .column
97
- )
98
- .frame(height: 200)
99
- }
100
-
101
- section("Custom renderIcon") {
102
- MomoTabView(
103
- tabs: [
104
- TabViewItem(
105
- title: "Custom",
106
- renderIcon: { active in
107
- AnyView(
108
- RoundedRectangle(cornerRadius: 12)
109
- .fill(active ? Colors.pink09 : Colors.black17)
110
- .frame(width: 24, height: 24)
111
- )
112
- }
113
- ) { tabContent("Custom Icon", Colors.pink09) },
114
- TabViewItem(title: "Normal", icon: "basic_search") { tabContent("Normal", Colors.blue08) },
115
- ]
116
- )
117
- .frame(height: 160)
118
- }
11
+ @ViewBuilder
12
+ private func tvContent(_ label: String, _ background: Color) -> some View {
13
+ ZStack {
14
+ background
15
+ MomoText(label, typography: .headerSSemibold, color: Colors.text)
16
+ }
17
+ .frame(maxWidth: .infinity)
18
+ .frame(height: 120)
19
+ }
119
20
 
120
- section("Swipe enabled") {
121
- MomoTabView(
122
- tabs: [
123
- TabViewItem(title: "Swipe 1") { tabContent("Swipe left/right", Colors.pink09) },
124
- TabViewItem(title: "Swipe 2") { tabContent("Swipeable!", Colors.blue08) },
125
- ],
126
- userScrollEnabled: true
127
- )
128
- .frame(height: 160)
129
- }
21
+ private let tabViewTypeList: [PlaygroundOption] = [
22
+ .init("default", TabViewType.default),
23
+ .init("card", TabViewType.card),
24
+ ]
130
25
 
131
- section("Column direction card type") {
132
- MomoTabView(
133
- tabs: [
134
- TabViewItem(title: "Personal", icon: "basic_home") { tabContent("Personal", Colors.pink09) },
135
- TabViewItem(title: "Business", icon: "basic_search") { tabContent("Business", Colors.blue08) },
136
- ],
137
- type: .card,
138
- direction: .column
139
- )
140
- .frame(height: 200)
141
- }
26
+ private let tabViewDirectionList: [PlaygroundOption] = [
27
+ .init("row", TabViewDirection.row),
28
+ .init("column", TabViewDirection.column),
29
+ ]
142
30
 
143
- section("fitContent (no pager)") {
144
- MomoTabView(
145
- tabs: [
146
- TabViewItem(title: "Tab A") { tabContent("Tab A content", Colors.pink09) },
147
- TabViewItem(title: "Tab B") { tabContent("Tab B content", Colors.blue08) },
148
- TabViewItem(title: "Tab C") { tabContent("Tab C content", Colors.green08) },
149
- ],
150
- fitContent: true
151
- )
152
- }
153
- }
154
- .padding(.vertical, 16)
31
+ struct TabViewDemo: View {
32
+ var body: some View {
33
+ if #available(iOS 16.0, *) {
34
+ DemoScreen(preview: { TabViewPreview() }, playground: { TabViewPlayground() })
35
+ } else {
36
+ Text("Requires iOS 16+").padding()
155
37
  }
156
38
  }
39
+ }
157
40
 
158
- // MARK: - Helpers
41
+ // MARK: - Preview
159
42
 
160
- @ViewBuilder
161
- private func section<Content: View>(
162
- _ title: String,
163
- @ViewBuilder content: () -> Content
164
- ) -> some View {
165
- VStack(alignment: .leading, spacing: 12) {
166
- Text(title)
167
- .font(.headline)
168
- content()
43
+ private struct TabViewPreview: View {
44
+ var body: some View {
45
+ BasicColumnBox("Default (2 tabs)", alignment: .leading) {
46
+ MomoTabView(tabs: [
47
+ TabViewItem(title: "Tab 1") { tvContent("Content 1", Colors.pink09) },
48
+ TabViewItem(title: "Tab 2") { tvContent("Content 2", Colors.blue08) },
49
+ ])
50
+ .frame(height: 160)
169
51
  }
170
- .padding(.horizontal, 16)
171
- }
172
-
173
- @ViewBuilder
174
- private func tabContent(_ label: String, _ background: Color) -> some View {
175
- ZStack {
176
- background
177
- MomoText(label, typography: .headerSSemibold, color: Colors.text)
52
+ BasicColumnBox("With badge & dot", alignment: .leading) {
53
+ MomoTabView(tabs: [
54
+ TabViewItem(title: "Inbox", badgeValue: "5") { tvContent("Inbox", Colors.orange08) },
55
+ TabViewItem(title: "Alerts", showDot: true, dotSize: .small) { tvContent("Alerts", Colors.red08) },
56
+ TabViewItem(title: "Done") { tvContent("Done", Colors.green08) },
57
+ ])
58
+ .frame(height: 160)
59
+ }
60
+ BasicColumnBox("Card type", alignment: .leading) {
61
+ MomoTabView(tabs: [
62
+ TabViewItem(title: "Personal") { tvContent("Personal", Colors.pink09) },
63
+ TabViewItem(title: "Business") { tvContent("Business", Colors.blue08) },
64
+ ], type: .card)
65
+ .frame(height: 160)
66
+ }
67
+ BasicColumnBox("Scrollable (many tabs)", alignment: .leading) {
68
+ MomoTabView(tabs: [
69
+ TabViewItem(title: "Monday") { tvContent("Monday", Colors.pink09) },
70
+ TabViewItem(title: "Tuesday") { tvContent("Tuesday", Colors.blue08) },
71
+ TabViewItem(title: "Wednesday") { tvContent("Wednesday", Colors.green08) },
72
+ TabViewItem(title: "Thursday") { tvContent("Thursday", Colors.orange08) },
73
+ TabViewItem(title: "Friday") { tvContent("Friday", Colors.mint08) },
74
+ ], scrollable: true)
75
+ .frame(height: 160)
178
76
  }
179
- .frame(maxWidth: .infinity)
180
- .frame(height: 120)
181
77
  }
182
78
  }
183
79
 
184
- #if DEBUG
185
- struct TabViewDemo_Previews: PreviewProvider {
186
- static var previews: some View {
187
- TabViewDemo()
80
+ // MARK: - Playground
81
+
82
+ @available(iOS 16.0, *)
83
+ private struct TabViewPlayground: View {
84
+ @State private var type: PlaygroundOption? = tabViewTypeList.first { $0.key == "default" }
85
+ @State private var direction: PlaygroundOption? = tabViewDirectionList.first { $0.key == "row" }
86
+ @State private var scrollable = false
87
+ @State private var fitContent = false
88
+
89
+ var body: some View {
90
+ PlaygroundTab(
91
+ component: {
92
+ MomoTabView(
93
+ tabs: [
94
+ TabViewItem(title: "Home", icon: "basic_home") { tvContent("Home", Colors.pink09) },
95
+ TabViewItem(title: "Search", icon: "basic_search") { tvContent("Search", Colors.blue08) },
96
+ TabViewItem(title: "Profile") { tvContent("Profile", Colors.green08) },
97
+ ],
98
+ type: (type?.value as? TabViewType) ?? .default,
99
+ scrollable: scrollable,
100
+ fitContent: fitContent,
101
+ direction: (direction?.value as? TabViewDirection) ?? .row
102
+ )
103
+ .frame(height: fitContent ? nil : 200)
104
+ .id("\(type?.key ?? "")-\(direction?.key ?? "")-\(scrollable)-\(fitContent)")
105
+ },
106
+ params: [
107
+ .radio("Type", tabViewTypeList, $type),
108
+ .radio("Direction", tabViewDirectionList, $direction),
109
+ .checkbox("Scrollable", $scrollable),
110
+ .checkbox("FitContent", $fitContent),
111
+ ]
112
+ )
188
113
  }
189
114
  }
190
- #endif