@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,72 +2,87 @@
2
2
  // InputOTPDemo.swift
3
3
  // Example
4
4
  //
5
- // Mirrors Compose `InputOTPUsage` (Preview cases): floating value, placeholder,
6
- // error message, error spacing, and a fixed-length numeric variant.
5
+ // Preview + Playground demo for InputOTP.
7
6
  //
8
7
 
9
8
  import MoMoUIKits
10
9
  import SwiftUI
11
10
 
12
- struct InputOTPDemo: View {
13
- @State private var value1 = ""
14
- @State private var value2 = ""
15
- @State private var value3 = ""
16
- @State private var value4 = ""
17
- @State private var value5 = ""
11
+ // Component-specific option maps (mirror otpLengthList / otpDataTypeList in DemoScreen.kt).
12
+ private let otpLengthList: [PlaygroundOption] = [
13
+ .init("2", 2), .init("4", 4), .init("6", 6), .init("8", 8), .init("10", 10),
14
+ ]
15
+ private let otpDataTypeList: [PlaygroundOption] = [
16
+ .init("number", "number"), .init("string", "string"),
17
+ ]
18
18
 
19
+ struct InputOTPDemo: View {
19
20
  var body: some View {
20
- ScrollView {
21
- VStack(alignment: .leading, spacing: 24) {
22
- section("Floating Value") {
23
- InputOTP(
24
- value: $value1,
25
- floatingValue: "Nhập mã xác thực OTP"
26
- )
27
- }
28
-
29
- section("Placeholder") {
30
- InputOTP(
31
- value: $value2,
32
- floatingValue: "",
33
- placeholder: "Placeholder text"
34
- )
35
- }
21
+ if #available(iOS 16.0, *) {
22
+ DemoScreen(preview: { InputOTPPreview() }, playground: { InputOTPPlayground() })
23
+ } else {
24
+ Text("Requires iOS 16+").padding()
25
+ }
26
+ }
27
+ }
36
28
 
37
- section("Error Message") {
38
- InputOTP(
39
- value: $value3,
40
- errorMessage: "Error",
41
- floatingValue: ""
42
- )
43
- }
29
+ // MARK: - Preview
44
30
 
45
- section("Error Spacing") {
46
- InputOTP(
47
- value: $value4,
48
- errorSpacing: true,
49
- floatingValue: ""
50
- )
51
- }
31
+ private struct InputOTPPreview: View {
32
+ @State private var v1 = ""
33
+ @State private var v2 = ""
34
+ @State private var v3 = ""
35
+ @State private var v4 = ""
52
36
 
53
- section("Data Type (length 6, number)") {
54
- InputOTP(
55
- value: $value5,
56
- length: 6,
57
- floatingValue: "",
58
- dataType: "number"
59
- )
60
- }
61
- }
62
- .padding(16)
37
+ var body: some View {
38
+ BasicColumnBox("Floating Value", alignment: .leading) {
39
+ InputOTP(value: $v1, floatingValue: "Nhập mã xác thực OTP")
40
+ }
41
+ BasicColumnBox("Placeholder", alignment: .leading) {
42
+ InputOTP(value: $v2, floatingValue: "", placeholder: "Placeholder text")
43
+ }
44
+ BasicColumnBox("Error Message", alignment: .leading) {
45
+ InputOTP(value: $v3, errorMessage: "Error", floatingValue: "")
46
+ }
47
+ BasicColumnBox("Length 6, number", alignment: .leading) {
48
+ InputOTP(value: $v4, length: 6, floatingValue: "", dataType: "number")
63
49
  }
64
50
  }
51
+ }
65
52
 
66
- @ViewBuilder
67
- private func section<Content: View>(_ title: String, @ViewBuilder content: () -> Content) -> some View {
68
- VStack(alignment: .leading, spacing: 8) {
69
- MomoText(title, typography: .headerSSemibold)
70
- content()
71
- }
53
+ // MARK: - Playground
54
+
55
+ @available(iOS 16.0, *)
56
+ private struct InputOTPPlayground: View {
57
+ @State private var value = ""
58
+ @State private var floatingValue = "Label"
59
+ @State private var placeholder = ""
60
+ @State private var errorMessage = ""
61
+ @State private var length: PlaygroundOption? = otpLengthList.first { $0.key == "6" }
62
+ @State private var dataType: PlaygroundOption? = otpDataTypeList.first { $0.key == "number" }
63
+ @State private var errorSpacing = false
64
+
65
+ var body: some View {
66
+ PlaygroundTab(
67
+ component: {
68
+ InputOTP(
69
+ value: $value,
70
+ length: length?.value as? Int,
71
+ errorMessage: errorMessage,
72
+ errorSpacing: errorSpacing,
73
+ floatingValue: floatingValue,
74
+ placeholder: placeholder,
75
+ dataType: (dataType?.value as? String) ?? "number"
76
+ )
77
+ },
78
+ params: [
79
+ .string("FloatingValue", $floatingValue),
80
+ .string("Placeholder", $placeholder),
81
+ .string("ErrorMessage", $errorMessage),
82
+ .radio("Length", otpLengthList, $length),
83
+ .radio("DataType", otpDataTypeList, $dataType),
84
+ .checkbox("ErrorSpacing", $errorSpacing),
85
+ ]
86
+ )
72
87
  }
73
88
  }
@@ -2,67 +2,87 @@
2
2
  // InputPhoneNumberDemo.swift
3
3
  // Example
4
4
  //
5
- // Created by sophia on 20/10/25.
5
+ // Preview + Playground demo for InputPhoneNumber.
6
6
  //
7
7
 
8
- import SwiftUI
9
8
  import MoMoUIKits
9
+ import SwiftUI
10
10
 
11
11
  public struct InputPhoneNumberDemo: View {
12
- @State private var textValue1 = ""
13
- @State private var textValue2 = ""
14
- @State private var textValue3 = ""
15
- @State private var textValue4 = ""
16
- @State private var textValue5 = ""
17
- @State private var textValue6 = ""
18
- @State private var textValue7 = ""
19
- @State private var textValue8 = ""
20
- @State private var textValue9 = ""
21
-
12
+ public init() {}
13
+
22
14
  public var body: some View {
23
- ScrollView {
24
- VStack(alignment: .leading, spacing: 20) {
25
- Text("Input Phone Number Demo")
26
- .font(.title1)
27
-
28
- Group {
29
- Text("Size")
30
- .font(.headerText1)
31
-
32
- InputPhoneNumber(text: $textValue1, placeholder: "Small", size: .small, autofocus: true, accessibilityLabel: "ehjgfruweyg")
33
- InputPhoneNumber(text: $textValue2, placeholder: "Large", size: .large)
34
- }
35
-
36
- Group {
37
- Text("Hint text")
38
- .font(.headerText1)
39
-
40
- InputPhoneNumber(text: $textValue3, placeholder: "Enter here", hintText: "Hint text")
41
- }
42
-
43
- Group {
44
- Text("Error")
45
- .font(.headerText1)
46
-
47
- InputPhoneNumber(text: $textValue4, placeholder: "Enter here", error: "error message")
48
- }
49
-
50
- Group {
51
- Text("Loading")
52
- .font(.headerText1)
53
-
54
- InputPhoneNumber(text: $textValue8, placeholder: "Loading", loading: true)
55
- }
56
-
57
- Group {
58
- Text("Trailing Icon")
59
- .font(.headerText1)
60
-
61
- InputPhoneNumber(text: $textValue9, placeholder: "Font Weight", rightIcon: "24_ic_public", rightIconColor: Colors.pink03)
62
- }
63
- }
64
- .padding()
15
+ if #available(iOS 16.0, *) {
16
+ DemoScreen(preview: { InputPhoneNumberPreview() }, playground: { InputPhoneNumberPlayground() })
17
+ } else {
18
+ Text("Requires iOS 16+").padding()
19
+ }
20
+ }
21
+ }
22
+
23
+ // MARK: - Preview
24
+
25
+ private struct InputPhoneNumberPreview: View {
26
+ @State private var t1 = ""
27
+ @State private var t2 = ""
28
+ @State private var t3 = ""
29
+ @State private var t4 = ""
30
+ @State private var t5 = ""
31
+
32
+ var body: some View {
33
+ BasicColumnBox("Size", alignment: .leading) {
34
+ InputPhoneNumber(text: $t1, placeholder: "Small", size: .small)
35
+ InputPhoneNumber(text: $t2, placeholder: "Large", size: .large)
36
+ }
37
+ BasicColumnBox("Hint text", alignment: .leading) {
38
+ InputPhoneNumber(text: $t3, placeholder: "Enter here", hintText: "Hint text")
39
+ }
40
+ BasicColumnBox("Error", alignment: .leading) {
41
+ InputPhoneNumber(text: $t4, placeholder: "Enter here", error: "error message")
65
42
  }
43
+ BasicColumnBox("Trailing Icon", alignment: .leading) {
44
+ InputPhoneNumber(text: $t5, placeholder: "Phone", rightIcon: "24_ic_public", rightIconColor: Colors.pink03)
45
+ }
46
+ }
47
+ }
48
+
49
+ // MARK: - Playground
50
+
51
+ @available(iOS 16.0, *)
52
+ private struct InputPhoneNumberPlayground: View {
53
+ @State private var text = ""
54
+ @State private var placeholder = "0123456789"
55
+ @State private var hintText = ""
56
+ @State private var error = ""
57
+ @State private var size: PlaygroundOption? = inputSizeList.first { $0.key == "small" }
58
+ @State private var rightIcon: PlaygroundOption?
59
+ @State private var loading = false
60
+ @State private var required = false
61
+
62
+ var body: some View {
63
+ PlaygroundTab(
64
+ component: {
65
+ InputPhoneNumber(
66
+ text: $text,
67
+ placeholder: placeholder,
68
+ size: (size?.value as? InputSize) ?? .small,
69
+ hintText: hintText,
70
+ error: error,
71
+ loading: loading,
72
+ required: required,
73
+ rightIcon: (rightIcon?.value as? String) ?? ""
74
+ )
75
+ },
76
+ params: [
77
+ .string("Placeholder", $placeholder),
78
+ .string("HintText", $hintText),
79
+ .string("Error", $error),
80
+ .radio("Size", inputSizeList, $size),
81
+ .option("RightIcon", playgroundIcons, $rightIcon),
82
+ .checkbox("Loading", $loading),
83
+ .checkbox("Required", $required),
84
+ ]
85
+ )
66
86
  }
67
87
  }
68
88
 
@@ -2,31 +2,84 @@
2
2
  // InputSearchDemo.swift
3
3
  // Example
4
4
  //
5
- // Created by dung.pham2 on 3/12/24.
5
+ // Preview + Playground demo for InputSearch.
6
6
  //
7
7
 
8
- import SwiftUI
9
8
  import MoMoUIKits
10
-
11
- // Your imports remain the same
9
+ import SwiftUI
12
10
 
13
11
  public struct InputSearchDemo: View {
14
- @State private var text = ""
15
-
12
+ public init() {}
13
+
16
14
  public var body: some View {
17
- VStack(alignment: .leading, spacing: 16) {
18
- Spacer().frame(height: 12)
19
-
20
- InputSearch(
21
- text: $text,
22
- buttonText: "Huỷ",
23
- showButtonText: true,
24
- placeholder: "Search",
25
- onChangeText: { newText in
26
- text = newText
27
- },
28
- icon: "24_navigation_close_circle_full"
29
- )
30
- }.frame(height: 40).padding()
15
+ if #available(iOS 16.0, *) {
16
+ DemoScreen(preview: { InputSearchPreview() }, playground: { InputSearchPlayground() })
17
+ } else {
18
+ Text("Requires iOS 16+").padding()
19
+ }
20
+ }
21
+ }
22
+
23
+ // MARK: - Preview
24
+
25
+ private struct InputSearchPreview: View {
26
+ @State private var t1 = ""
27
+ @State private var t2 = ""
28
+ @State private var t3 = ""
29
+
30
+ var body: some View {
31
+ BasicColumnBox("Default", alignment: .leading) {
32
+ InputSearch(text: $t1, placeholder: "Search")
33
+ .frame(height: 40)
34
+ }
35
+ BasicColumnBox("With cancel button", alignment: .leading) {
36
+ InputSearch(text: $t2, buttonText: "Huỷ", showButtonText: true, placeholder: "Search")
37
+ .frame(height: 40)
38
+ }
39
+ BasicColumnBox("Disabled", alignment: .leading) {
40
+ InputSearch(text: $t3, placeholder: "Search", disabled: true)
41
+ .frame(height: 40)
42
+ }
43
+ }
44
+ }
45
+
46
+ // MARK: - Playground
47
+
48
+ @available(iOS 16.0, *)
49
+ private struct InputSearchPlayground: View {
50
+ @State private var text = ""
51
+ @State private var placeholder = "Search"
52
+ @State private var buttonText = "Huỷ"
53
+ @State private var error = ""
54
+ @State private var showButtonText = false
55
+ @State private var showBorder = true
56
+ @State private var disabled = false
57
+ @State private var loading = false
58
+
59
+ var body: some View {
60
+ PlaygroundTab(
61
+ component: {
62
+ InputSearch(
63
+ text: $text,
64
+ buttonText: buttonText,
65
+ showButtonText: showButtonText,
66
+ showBorder: showBorder,
67
+ placeholder: placeholder,
68
+ error: error,
69
+ disabled: disabled,
70
+ loading: loading
71
+ )
72
+ .frame(height: 40)
73
+ },
74
+ params: [
75
+ .string("Placeholder", $placeholder),
76
+ .string("ButtonText", $buttonText),
77
+ .string("Error", $error),
78
+ .checkbox("ShowButtonText", $showButtonText),
79
+ .checkbox("ShowBorder", $showBorder),
80
+ .checkbox("Disabled", $disabled),
81
+ .checkbox("Loading", $loading),
82
+ ]
83
+ )
31
84
  }
32
85
  }
@@ -2,56 +2,86 @@
2
2
  // InputTextAreaDemo.swift
3
3
  // Example
4
4
  //
5
- // Created by dung.pham2 on 2/12/24.
5
+ // Preview + Playground demo for InputTextArea.
6
6
  //
7
- import SwiftUI
7
+
8
8
  import MoMoUIKits
9
+ import SwiftUI
9
10
 
10
11
  struct InputTextAreaDemo: View {
11
12
  var body: some View {
12
- NavigationView {
13
- ScrollView {
14
- VStack(alignment: .leading, spacing: 16) {
15
- Text("Preview")
16
- .font(.headline)
17
-
18
- TextAreaPreview()
19
-
20
- // Text("Playground")
21
- // .font(.headline)
22
-
23
- // TextAreaPlayground()
24
- }
25
- .padding()
26
- }
27
-
13
+ if #available(iOS 16.0, *) {
14
+ DemoScreen(preview: { TextAreaPreview() }, playground: { TextAreaPlayground() })
15
+ } else {
16
+ Text("Requires iOS 16+").padding()
28
17
  }
29
18
  }
30
19
  }
31
20
 
32
- struct TextAreaPreview: View {
21
+ // MARK: - Preview
22
+
23
+ private struct TextAreaPreview: View {
33
24
  @State private var text = ""
34
- let url = "https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/momomain_momo.png"
35
-
25
+ private let url = "https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/momomain_momo.png"
26
+
36
27
  var body: some View {
37
- VStack(alignment: .leading, spacing: 8) {
38
- Text("Floating Value")
39
- InputTextArea(text: $text,
40
- floatingValue: "Momo",
41
- floatingIcon: url, floatingIconColor: Colors.pink03)
42
-
43
- Text("Error")
44
- InputTextArea(text: .constant("Error"),
45
- error: "Error")
46
-
47
- Text("Error Spacing")
48
- InputTextArea(text: .constant("Error"),
49
- errorSpacing: true)
50
-
51
- Text("Disabled")
52
- InputTextArea(text: .constant("Disabled"),
53
- disabled: true)
28
+ BasicColumnBox("Floating Value", alignment: .leading) {
29
+ InputTextArea(text: $text, floatingValue: "Momo", floatingIcon: url, floatingIconColor: Colors.pink03)
30
+ }
31
+ BasicColumnBox("Error", alignment: .leading) {
32
+ InputTextArea(text: .constant("Error"), error: "Error")
33
+ }
34
+ BasicColumnBox("Error Spacing", alignment: .leading) {
35
+ InputTextArea(text: .constant("Error"), errorSpacing: true)
36
+ }
37
+ BasicColumnBox("Disabled", alignment: .leading) {
38
+ InputTextArea(text: .constant("Disabled"), disabled: true)
54
39
  }
55
40
  }
56
41
  }
57
42
 
43
+ // MARK: - Playground
44
+
45
+ @available(iOS 16.0, *)
46
+ private struct TextAreaPlayground: View {
47
+ @State private var text = ""
48
+ @State private var placeholder = "Enter text"
49
+ @State private var floatingValue = "Label"
50
+ @State private var error = ""
51
+ @State private var maxLength = "200"
52
+ @State private var height: Double = 120
53
+ @State private var disabled = false
54
+ @State private var errorSpacing = false
55
+ @State private var loading = false
56
+ @State private var required = false
57
+
58
+ var body: some View {
59
+ PlaygroundTab(
60
+ component: {
61
+ InputTextArea(
62
+ text: $text,
63
+ maxLength: Int(maxLength) ?? 200,
64
+ height: CGFloat(height),
65
+ floatingValue: floatingValue,
66
+ placeholder: placeholder,
67
+ error: error,
68
+ errorSpacing: errorSpacing,
69
+ disabled: disabled,
70
+ loading: loading,
71
+ required: required
72
+ )
73
+ },
74
+ params: [
75
+ .string("Placeholder", $placeholder),
76
+ .string("FloatingValue", $floatingValue),
77
+ .string("Error", $error),
78
+ .number("MaxLength", $maxLength),
79
+ .slider("Height", $height, min: 60, max: 240, step: 10),
80
+ .checkbox("Disabled", $disabled),
81
+ .checkbox("ErrorSpacing", $errorSpacing),
82
+ .checkbox("Loading", $loading),
83
+ .checkbox("Required", $required),
84
+ ]
85
+ )
86
+ }
87
+ }
@@ -2,69 +2,72 @@
2
2
  // LoaderDemo.swift
3
3
  // Example
4
4
  //
5
- // Mirrors sample/shared LoaderUsage.kt
5
+ // Preview + Playground demo for Loader / DotLoader / SpinnerLoader / ProgressBar.
6
6
  //
7
7
 
8
- import SwiftUI
9
8
  import MoMoUIKits
9
+ import SwiftUI
10
10
 
11
- struct LoaderDemo: View {
12
- @State private var progress: CGFloat = 50
11
+ private let loaderTypeList: [PlaygroundOption] = [
12
+ .init("dot", LoaderType.dot),
13
+ .init("spinner", LoaderType.spinner),
14
+ ]
13
15
 
16
+ struct LoaderDemo: View {
14
17
  var body: some View {
15
- ScrollView {
16
- VStack(alignment: .leading, spacing: 24) {
17
- row("DotLoader (default)") {
18
- DotLoader()
19
- }
20
- row("DotLoader with tint") {
21
- DotLoader(tintColor: Colors.pink03)
22
- }
23
- row("SpinnerLoader (default)") {
24
- SpinnerLoader()
25
- }
26
- row("SpinnerLoader with tint") {
27
- SpinnerLoader(tintColor: Colors.pink03)
28
- }
29
- row("Loader(type: .dot)") {
30
- Loader(type: .dot)
31
- }
32
- row("Loader(type: .spinner)") {
33
- Loader(type: .spinner, tintColor: Colors.pink03)
34
- }
35
- row("ProgressBar 0%") {
36
- ProgressBar(percent: 0)
37
- }
38
- row("ProgressBar 40%") {
39
- ProgressBar(percent: 40)
40
- }
41
- row("ProgressBar 100%") {
42
- ProgressBar(percent: 100)
43
- }
44
- row("ProgressBar with tint (65%)") {
45
- ProgressBar(percent: 65, color: Colors.pink03)
46
- }
47
- VStack(alignment: .leading, spacing: 8) {
48
- Text("ProgressBar (interactive: \(Int(progress))%)")
49
- .font(.subheadline)
50
- ProgressBar(percent: progress, color: Colors.pink03)
51
- Slider(value: $progress, in: 0...100)
52
- }
53
- }
54
- .padding()
18
+ if #available(iOS 16.0, *) {
19
+ DemoScreen(preview: { LoaderPreview() }, playground: { LoaderPlayground() })
20
+ } else {
21
+ Text("Requires iOS 16+").padding()
55
22
  }
56
23
  }
24
+ }
57
25
 
58
- @ViewBuilder
59
- private func row<Content: View>(_ title: String, @ViewBuilder content: () -> Content) -> some View {
60
- VStack(alignment: .leading, spacing: 8) {
61
- Text(title)
62
- .font(.subheadline)
63
- content()
26
+ // MARK: - Preview
27
+
28
+ private struct LoaderPreview: View {
29
+ var body: some View {
30
+ BasicColumnBox("DotLoader", alignment: .leading) {
31
+ DotLoader()
32
+ DotLoader(tintColor: Colors.pink03)
33
+ }
34
+ BasicColumnBox("SpinnerLoader", alignment: .leading) {
35
+ SpinnerLoader()
36
+ SpinnerLoader(tintColor: Colors.pink03)
37
+ }
38
+ BasicColumnBox("ProgressBar", alignment: .leading) {
39
+ ProgressBar(percent: 0)
40
+ ProgressBar(percent: 40)
41
+ ProgressBar(percent: 100)
42
+ ProgressBar(percent: 65, color: Colors.pink03)
64
43
  }
65
44
  }
66
45
  }
67
46
 
68
- #Preview {
69
- LoaderDemo()
47
+ // MARK: - Playground
48
+
49
+ @available(iOS 16.0, *)
50
+ private struct LoaderPlayground: View {
51
+ @State private var type: PlaygroundOption? = loaderTypeList.first { $0.key == "dot" }
52
+ @State private var tint: PlaygroundOption? = playgroundColors.first { $0.key == "pink03" }
53
+ @State private var percent: Double = 65
54
+
55
+ var body: some View {
56
+ PlaygroundTab(
57
+ component: {
58
+ VStack(alignment: .leading, spacing: Spacing.L) {
59
+ Loader(
60
+ type: (type?.value as? LoaderType) ?? .dot,
61
+ tintColor: tint?.value as? Color
62
+ )
63
+ ProgressBar(percent: CGFloat(percent), color: tint?.value as? Color)
64
+ }
65
+ },
66
+ params: [
67
+ .radio("Type", loaderTypeList, $type),
68
+ .color("TintColor", playgroundColors, $tint),
69
+ .slider("ProgressBar percent", $percent, min: 0, max: 100, step: 1),
70
+ ]
71
+ )
72
+ }
70
73
  }