@momo-kits/native-kits 0.162.30-debug → 0.162.31-debug

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 (93) hide show
  1. package/CLAUDE.md +19 -0
  2. package/compose/build.gradle.kts +1 -1
  3. package/compose/compose.podspec +1 -1
  4. package/gradle.properties +1 -1
  5. package/ios/Application/ApplicationEnvironment.swift +14 -6
  6. package/ios/Application/LanguageSource.swift +93 -0
  7. package/ios/Application/Localize.swift +73 -4
  8. package/ios/Application/LocalizeModifier.swift +30 -0
  9. package/ios/Application/Navigation/NavigationContainer.swift +28 -18
  10. package/ios/Application/Navigation/Navigator.swift +121 -53
  11. package/ios/Application/Navigation/NavigatorManager.swift +49 -0
  12. package/ios/Application/Navigation/component/NavigationFooter.swift +90 -0
  13. package/ios/Application/StackScreen.swift +19 -28
  14. package/ios/Badge/Badge.swift +2 -1
  15. package/ios/Badge/BadgeRibbon.swift +6 -2
  16. package/ios/Button/Button.swift +41 -61
  17. package/ios/Chip/Chip.swift +6 -5
  18. package/ios/Icon/Icon.swift +13 -4
  19. package/ios/Input/ErrorView.swift +2 -1
  20. package/ios/Input/Input.swift +9 -2
  21. package/ios/Input/InputPhoneNumber.swift +2 -1
  22. package/ios/Input/InputSearch.swift +3 -2
  23. package/ios/Input/InputTextArea.swift +6 -1
  24. package/ios/InputMoney/InputMoney.swift +5 -2
  25. package/ios/InputOTP/InputOTP.swift +2 -1
  26. package/ios/Layout/GridContext.swift +30 -0
  27. package/ios/Layout/Item.swift +42 -0
  28. package/ios/Layout/Section.swift +134 -0
  29. package/ios/Popup/PopupNotify.swift +2 -1
  30. package/ios/ProgressInfo/ProgressInfo.swift +4 -3
  31. package/ios/Rating/Rating.swift +2 -1
  32. package/ios/Stepper/Stepper.swift +2 -1
  33. package/ios/SuggestAction/SuggestAction.swift +3 -2
  34. package/ios/Tag/Tag.swift +2 -1
  35. package/ios/Template/TrustBanner/TrustBanner.swift +4 -2
  36. package/ios/Title/Title.swift +3 -2
  37. package/ios/Tooltip/Tooltip.swift +2 -1
  38. package/ios/Typography/FontScale.swift +103 -0
  39. package/ios/Typography/FontScaleStore.swift +52 -13
  40. package/ios/Typography/Text.swift +12 -29
  41. package/ios/Typography/Typography.swift +66 -86
  42. package/ios/native-kits.podspec +2 -1
  43. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  44. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +87 -73
  45. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +55 -249
  46. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +90 -82
  47. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +74 -104
  48. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +47 -50
  49. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +63 -7
  50. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +90 -81
  51. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +73 -97
  52. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DemoScreen.swift +420 -0
  53. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +46 -4
  54. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +54 -57
  55. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +80 -45
  56. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconDemo.swift +81 -0
  57. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +49 -62
  58. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +66 -116
  59. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +104 -98
  60. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +76 -118
  61. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +73 -86
  62. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +69 -54
  63. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +74 -54
  64. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +73 -20
  65. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +68 -38
  66. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +55 -52
  67. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +51 -4
  68. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +14 -2
  69. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +47 -51
  70. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PlaygroundData.swift +76 -0
  71. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +67 -93
  72. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +34 -43
  73. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +83 -71
  74. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +55 -23
  75. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +58 -46
  76. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SectionDemo.swift +83 -0
  77. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +41 -12
  78. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +67 -127
  79. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +54 -110
  80. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +69 -79
  81. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +78 -58
  82. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +76 -65
  83. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +82 -127
  84. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +44 -19
  85. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +92 -168
  86. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +79 -27
  87. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +0 -1
  88. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +87 -92
  89. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +94 -163
  90. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +70 -70
  91. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +68 -114
  92. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +3 -1
  93. package/package.json +2 -2
@@ -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
@@ -1,34 +1,86 @@
1
- import SwiftUI
1
+ //
2
+ // TagDemo.swift
3
+ // Example
4
+ //
5
+ // Preview + Playground demo, mirroring Compose's TagUsage.kt.
6
+ //
7
+
2
8
  import MoMoUIKits
9
+ import SwiftUI
10
+
11
+ private let tagColorList: [PlaygroundOption] = [
12
+ .init("default", Tag.TagColor.default),
13
+ .init("orange", Tag.TagColor.orange),
14
+ .init("green", Tag.TagColor.green),
15
+ .init("red", Tag.TagColor.red),
16
+ .init("blue", Tag.TagColor.blue),
17
+ .init("grey", Tag.TagColor.grey),
18
+ ]
19
+
20
+ private let tagSizeList: [PlaygroundOption] = [
21
+ .init("large", Tag.TagSize.large),
22
+ .init("medium", Tag.TagSize.medium),
23
+ ]
3
24
 
4
25
  struct TagDemo: View {
5
26
  var body: some View {
6
- ScrollView {
7
- VStack(alignment: .leading, spacing: 24) {
8
- VStack(alignment: .leading, spacing: 8) {
9
- Text("Color").font(.headline)
10
- Tag()
11
- Tag(color: .red)
12
- Tag(color: .blue)
13
- Tag(color: .green)
14
- Tag(color: .orange)
15
- Tag(color: .grey)
16
- }
17
-
18
- VStack(alignment: .leading, spacing: 8) {
19
- Text("Size").font(.headline)
20
- Tag(size: .large)
21
- Tag(size: .medium)
22
- }
23
-
24
- VStack(alignment: .leading, spacing: 8) {
25
- Text("With Icon").font(.headline)
26
- Tag(icon: "ic_momo", color: .grey)
27
- Tag(icon: "ic_momo", color: .red, size: .medium)
28
- Tag(icon: "ic_momo", color: .blue, size: .medium)
29
- }
30
- }
31
- .padding()
27
+ if #available(iOS 16.0, *) {
28
+ DemoScreen(preview: { TagPreview() }, playground: { TagPlayground() })
29
+ } else {
30
+ Text("Requires iOS 16+").padding()
32
31
  }
33
32
  }
34
33
  }
34
+
35
+ // MARK: - Preview
36
+
37
+ private struct TagPreview: View {
38
+ var body: some View {
39
+ BasicColumnBox("Color", alignment: .leading) {
40
+ Tag()
41
+ Tag(color: .red)
42
+ Tag(color: .blue)
43
+ Tag(color: .green)
44
+ Tag(color: .orange)
45
+ Tag(color: .grey)
46
+ }
47
+ BasicColumnBox("Size", alignment: .leading) {
48
+ Tag(size: .large)
49
+ Tag(size: .medium)
50
+ }
51
+ BasicColumnBox("With Icon", alignment: .leading) {
52
+ Tag(icon: "ic_momo", color: .grey)
53
+ Tag(icon: "ic_momo", color: .red, size: .medium)
54
+ Tag(icon: "ic_momo", color: .blue, size: .medium)
55
+ }
56
+ }
57
+ }
58
+
59
+ // MARK: - Playground
60
+
61
+ @available(iOS 16.0, *)
62
+ private struct TagPlayground: View {
63
+ @State private var label = "Label"
64
+ @State private var color: PlaygroundOption? = tagColorList.first { $0.key == "default" }
65
+ @State private var size: PlaygroundOption? = tagSizeList.first { $0.key == "large" }
66
+ @State private var icon: PlaygroundOption?
67
+
68
+ var body: some View {
69
+ PlaygroundTab(
70
+ component: {
71
+ Tag(
72
+ label: label,
73
+ icon: icon?.value as? String,
74
+ color: (color?.value as? Tag.TagColor) ?? .default,
75
+ size: (size?.value as? Tag.TagSize) ?? .large
76
+ )
77
+ },
78
+ params: [
79
+ .string("Label", $label),
80
+ .radio("Color", tagColorList, $color),
81
+ .radio("Size", tagSizeList, $size),
82
+ .option("Icon", playgroundIcons, $icon),
83
+ ]
84
+ )
85
+ }
86
+ }
@@ -90,7 +90,6 @@ struct ThemeDemo: View {
90
90
  Spacer(minLength: 32)
91
91
  }
92
92
  }
93
- .navigationTitle("Theme")
94
93
  .background(isDarkMode ? Colors.black10.ignoresSafeArea() : theme.colors.background.default.ignoresSafeArea())
95
94
  .environment(\.appTheme, isDarkMode ? darkTheme : defaultTheme)
96
95
  }
@@ -2,108 +2,103 @@
2
2
  // TitleDemo.swift
3
3
  // Example
4
4
  //
5
- import SwiftUI
5
+ // Preview + Playground demo (DemoScreen pattern).
6
+ //
7
+
6
8
  import MoMoUIKits
9
+ import SwiftUI
7
10
 
8
- struct TitleDemo: View {
9
- var body: some View {
10
- ScrollView {
11
- VStack(alignment: .leading, spacing: 24) {
12
- section("Section Type") {
13
- Title(
14
- title: "Section Small",
15
- type: .section,
16
- size: .small
17
- )
18
- Title(
19
- title: "Section Medium",
20
- type: .section,
21
- size: .medium,
22
- icon: "basic_home",
23
- description: "This is a medium section with icon."
24
- )
25
- Title(
26
- title: "Section Large",
27
- type: .section,
28
- size: .large,
29
- showTrailingAction: true,
30
- badgeLabel: "NEW",
31
- onPressTrailingAction: { }
32
- )
33
- }
11
+ private let titleTypeList: [PlaygroundOption] = [
12
+ .init("card", TitleType.card),
13
+ .init("section", TitleType.section),
14
+ ]
15
+
16
+ private let titleSizeList: [PlaygroundOption] = [
17
+ .init("small", TitleSize.small),
18
+ .init("medium", TitleSize.medium),
19
+ .init("large", TitleSize.large),
20
+ ]
34
21
 
35
- section("Card Type") {
36
- Title(
37
- title: "Card Small Text Only",
38
- type: .card,
39
- size: .small,
40
- textOnly: true
41
- )
42
- Title(
43
- title: "Card Medium with Right Action",
44
- type: .card,
45
- size: .medium,
46
- icon: "basic_home",
47
- showRightAction: true,
48
- buttonTitle: "Action",
49
- onPressRightAction: { }
50
- )
51
- Title(
52
- title: "Card Large Full",
53
- type: .card,
54
- size: .large,
55
- icon: "basic_home",
56
- showRightAction: true,
57
- badgeLabel: "99+",
58
- onPressRightAction: { },
59
- description: "A large card title with description, badge and right arrow."
60
- )
61
- }
22
+ private let iconAlignList: [PlaygroundOption] = [
23
+ .init("top", IconAlign.top),
24
+ .init("center", IconAlign.center),
25
+ .init("bottom", IconAlign.bottom),
26
+ ]
62
27
 
63
- section("Icon Alignment") {
64
- Title(
65
- title: "Icon Top",
66
- type: .section,
67
- icon: "basic_home",
68
- iconAlign: .top,
69
- description: "Icon aligned to top"
70
- )
71
- Title(
72
- title: "Icon Center",
73
- type: .section,
74
- icon: "basic_home",
75
- iconAlign: .center,
76
- description: "Icon aligned to center"
77
- )
78
- Title(
79
- title: "Icon Bottom",
80
- type: .section,
81
- icon: "basic_home",
82
- iconAlign: .bottom,
83
- description: "Icon aligned to bottom"
84
- )
85
- }
86
- }
87
- .padding(16)
28
+ struct TitleDemo: View {
29
+ var body: some View {
30
+ if #available(iOS 16.0, *) {
31
+ DemoScreen(preview: { TitlePreview() }, playground: { TitlePlayground() })
32
+ } else {
33
+ Text("Requires iOS 16+").padding()
88
34
  }
89
35
  }
36
+ }
37
+
38
+ // MARK: - Preview
90
39
 
91
- @ViewBuilder
92
- private func section<Content: View>(
93
- _ title: String,
94
- @ViewBuilder content: () -> Content
95
- ) -> some View {
96
- VStack(alignment: .leading, spacing: 8) {
97
- MomoText(title, typography: .headerSSemibold, color: Colors.textSecondary)
98
- content()
40
+ private struct TitlePreview: View {
41
+ var body: some View {
42
+ BasicColumnBox("Section Type", alignment: .leading) {
43
+ Title(title: "Section Small", type: .section, size: .small)
44
+ Title(title: "Section Medium", type: .section, size: .medium, icon: "basic_home",
45
+ description: "This is a medium section with icon.")
46
+ Title(title: "Section Large", type: .section, size: .large,
47
+ showTrailingAction: true, badgeLabel: "NEW", onPressTrailingAction: {})
48
+ }
49
+ BasicColumnBox("Card Type", alignment: .leading) {
50
+ Title(title: "Card Small Text Only", type: .card, size: .small, textOnly: true)
51
+ Title(title: "Card Medium with Right Action", type: .card, size: .medium, icon: "basic_home",
52
+ showRightAction: true, buttonTitle: "Action", onPressRightAction: {})
53
+ }
54
+ BasicColumnBox("Icon Alignment", alignment: .leading) {
55
+ Title(title: "Icon Top", type: .section, icon: "basic_home", iconAlign: .top, description: "Aligned top")
56
+ Title(title: "Icon Center", type: .section, icon: "basic_home", iconAlign: .center, description: "Aligned center")
99
57
  }
100
58
  }
101
59
  }
102
60
 
103
- struct TitleDemo_Previews: PreviewProvider {
104
- static var previews: some View {
105
- NavigationView {
106
- TitleDemo()
107
- }
61
+ // MARK: - Playground
62
+
63
+ @available(iOS 16.0, *)
64
+ private struct TitlePlayground: View {
65
+ @State private var title = "Title"
66
+ @State private var type: PlaygroundOption? = titleTypeList.first { $0.key == "section" }
67
+ @State private var size: PlaygroundOption? = titleSizeList.first { $0.key == "medium" }
68
+ @State private var icon: PlaygroundOption?
69
+ @State private var iconAlign: PlaygroundOption? = iconAlignList.first { $0.key == "top" }
70
+ @State private var description = ""
71
+ @State private var badgeLabel = ""
72
+ @State private var showRightAction = false
73
+ @State private var textOnly = false
74
+
75
+ var body: some View {
76
+ PlaygroundTab(
77
+ component: {
78
+ Title(
79
+ title: title,
80
+ type: (type?.value as? TitleType) ?? .section,
81
+ size: (size?.value as? TitleSize) ?? .medium,
82
+ icon: (icon?.value as? String),
83
+ iconAlign: (iconAlign?.value as? IconAlign) ?? .top,
84
+ showRightAction: showRightAction,
85
+ badgeLabel: badgeLabel.isEmpty ? nil : badgeLabel,
86
+ onPressRightAction: {},
87
+ textOnly: textOnly,
88
+ description: description.isEmpty ? nil : description
89
+ )
90
+ },
91
+ params: [
92
+ .string("Title", $title),
93
+ .radio("Type", titleTypeList, $type),
94
+ .radio("Size", titleSizeList, $size),
95
+ .option("Icon", playgroundIcons, $icon),
96
+ .radio("IconAlign", iconAlignList, $iconAlign),
97
+ .string("Description", $description),
98
+ .string("BadgeLabel", $badgeLabel),
99
+ .checkbox("ShowRightAction", $showRightAction),
100
+ .checkbox("TextOnly", $textOnly),
101
+ ]
102
+ )
108
103
  }
109
104
  }