@momo-kits/native-kits 0.111.1-rc.2 → 0.112.1-rc.1

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.
@@ -39,15 +39,15 @@ fun getFont(font: String): FontFamily {
39
39
  fun getFontFamily(fontFamily: String, fontWeight: FontWeight? = FontWeight.Normal): FontFamily {
40
40
  val key = "$fontFamily-${fontWeight?.weight}"
41
41
  val fontMap = mapOf(
42
- "SFProText-100" to "sfprotext_thin.ttf",
43
- "SFProText-200" to "sfprotext_ultralight.ttf",
42
+ "SFProText-100" to "sfprotext_thin.otf",
43
+ "SFProText-200" to "sfprotext_ultralight.otf",
44
44
  "SFProText-300" to "sfprotext_light.ttf",
45
45
  "SFProText-400" to "sfprotext_regular.ttf",
46
46
  "SFProText-500" to "sfprotext_medium.ttf",
47
- "SFProText-600" to "sfprotext_medium.ttf",
48
- "SFProText-700" to "sfprotext_semibold.ttf",
49
- "SFProText-800" to "sfprotext_bold.ttf",
50
- "SFProText-900" to "sfprotext_heavy.ttf",
47
+ "SFProText-600" to "sfprotext_semibold.ttf",
48
+ "SFProText-700" to "sfprotext_bold.ttf",
49
+ "SFProText-800" to "sfprotext_heavy.ttf",
50
+ "SFProText-900" to "sfprotext_black.otf",
51
51
 
52
52
  "MoMoSignature-100" to "momosignature.otf",
53
53
  "MoMoSignature-200" to "momosignature.otf",
@@ -0,0 +1,223 @@
1
+ //
2
+ // Components.swift
3
+ // Pods
4
+ //
5
+ // Created by sophia on 24/1/25.
6
+ //
7
+
8
+ import SwiftUI
9
+
10
+ public enum TitlePosition {
11
+ case left, center
12
+ }
13
+
14
+ public enum HeaderType {
15
+ case `default`, extended, none
16
+ }
17
+
18
+
19
+ public struct AnimatedHeader {
20
+ public var type: HeaderType = .default
21
+ public var composable: (_ scrollState: Int) -> AnyView = { _ in AnyView(EmptyView()) }
22
+
23
+ public init(
24
+ type: HeaderType = .default,
25
+ composable: @escaping (_ scrollState: Int) -> AnyView = { _ in AnyView(EmptyView()) }
26
+ ) {
27
+ self.type = type
28
+ self.composable = composable
29
+ }
30
+ }
31
+
32
+ func safeAreaTopInset() -> CGFloat {
33
+ if #available(iOS 15.0, *) {
34
+ return UIApplication.shared.connectedScenes
35
+ .compactMap { ($0 as? UIWindowScene)?.keyWindow?.safeAreaInsets.top }
36
+ .first ?? 0
37
+ } else {
38
+ return UIApplication.shared.connectedScenes
39
+ .compactMap { ($0 as? UIWindowScene)?.windows.first?.safeAreaInsets.top }
40
+ .first ?? 0
41
+ }
42
+ }
43
+
44
+
45
+ public struct HeaderBackground: View {
46
+ var headerType: HeaderType = .default
47
+ var scrollState: CGFloat
48
+
49
+ public var body: some View {
50
+
51
+ let statusBarHeight = safeAreaTopInset()
52
+
53
+ let opacity = 1 - CGFloat(scrollState) / 200
54
+ let backgroundColor = scrollState == 0 ? Color.clear : Colors.black01
55
+
56
+ Group {
57
+ if headerType == .default {
58
+ let height = statusBarHeight + 52
59
+ ZStack {
60
+
61
+ Rectangle()
62
+ .fill(backgroundColor)
63
+ .frame(height: height)
64
+ .shadow(color: Colors.black20.opacity(0.2), radius: 10, x: 0, y: -2)
65
+ .overlay(Rectangle()
66
+ .fill(LinearGradient(
67
+ gradient: Gradient(colors: [
68
+ Color(red: 1, green: 0.8, blue: 0.87),
69
+ Color(red: 1, green: 0.8, blue: 0.87).opacity(0.5)
70
+ ]),
71
+ startPoint: .top,
72
+ endPoint: .bottom))
73
+ .opacity(opacity)
74
+ .frame(height: height))
75
+ .overlay(Rectangle()
76
+ .fill(Colors.black04)
77
+ .frame(height: 1)
78
+ .frame(maxWidth: .infinity)
79
+ .alignmentGuide(.bottom) { _ in 0 }, alignment: .bottom
80
+ )
81
+ }
82
+ .frame(maxWidth: .infinity)
83
+
84
+ } else if headerType == .extended {
85
+ ZStack {
86
+ Rectangle()
87
+ .fill(LinearGradient(
88
+ gradient: Gradient(colors: [
89
+ Color(red: 1, green: 0.8, blue: 0.87),
90
+ Color(red: 1, green: 0.8, blue: 0.87).opacity(0)
91
+ ]),
92
+ startPoint: .top,
93
+ endPoint: .bottom))
94
+ .opacity(opacity)
95
+ .frame(height: 154)
96
+
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ }
103
+
104
+ public struct Header: View {
105
+ var headerType: HeaderType = .default
106
+ var titlePosition: TitlePosition
107
+ var title: String
108
+ var headerRight: (() -> AnyView)?
109
+ var goBack: (() -> Void)?
110
+ var opacity: CGFloat? = nil
111
+ var animatedHeader: AnimatedHeader? = nil
112
+ var scrollState: CGFloat = 0
113
+ var inputSearchProps: InputSearchProps? = nil
114
+
115
+ @State private var colorFraction: CGFloat = 0
116
+
117
+ public init(
118
+ headerType: HeaderType = .default,
119
+ titlePosition: TitlePosition,
120
+ title: String,
121
+ headerRight: (() -> AnyView)? = nil,
122
+ goBack: (() -> Void)? = nil,
123
+ opacity: CGFloat? = nil,
124
+ animatedHeader: AnimatedHeader? = nil,
125
+ scrollState: CGFloat = 0,
126
+ inputSearchProps: InputSearchProps? = nil
127
+ ) {
128
+ self.headerType = headerType
129
+ self.titlePosition = titlePosition
130
+ self.title = title
131
+ self.headerRight = headerRight
132
+ self.goBack = goBack
133
+ self.opacity = opacity
134
+ self.animatedHeader = animatedHeader
135
+ self.scrollState = scrollState
136
+ self.inputSearchProps = inputSearchProps
137
+ }
138
+
139
+ public var body: some View {
140
+
141
+ let statusBarHeight = safeAreaTopInset()
142
+ let tintIconColor = Colors.black17
143
+ let backgroundButton = Colors.black01.opacity(0.6)
144
+
145
+ if headerType != .none {
146
+ VStack(spacing: 0) {
147
+ ZStack {
148
+ HStack {
149
+ if let goBack = goBack {
150
+ SwiftUI.Button(action: goBack) {
151
+ Circle()
152
+ .stroke(Color.black.opacity(0.2), lineWidth: 0.2)
153
+ .background(Circle().fill(backgroundButton))
154
+ .frame(width: 28, height: 28)
155
+ .overlay(
156
+ Image(systemName: "arrow.backward")
157
+ .foregroundColor(.black)
158
+ )
159
+ }
160
+
161
+ }
162
+
163
+ Spacer() // Pushes headerRight to the right
164
+
165
+ if let headerRight = headerRight {
166
+ headerRight()
167
+ }
168
+ }
169
+ .frame(height: 52)
170
+ .padding(.horizontal)
171
+
172
+
173
+
174
+ HStack {
175
+ if titlePosition == .left, goBack != nil {
176
+ Spacer().frame(width: 40)
177
+ }
178
+
179
+ if inputSearchProps != nil {
180
+ if let inputProps = inputSearchProps {
181
+ InputSearch(
182
+ text: inputProps.$text,
183
+ buttonText: inputProps.buttonText,
184
+ showButtonText: inputProps.showButtonText,
185
+ showBorder: inputProps.showBorder,
186
+ placeholder: inputProps.placeholder,
187
+ onChangeText: inputProps.onChangeText,
188
+ onPressButtonText: inputProps.onPressButtonText,
189
+ error: inputProps.error,
190
+ disabled: inputProps.disabled,
191
+ icon: inputProps.icon,
192
+ iconColor: inputProps.iconColor,
193
+ onRightIconPressed: inputProps.onRightIconPressed,
194
+ onFocus: inputProps.onFocus,
195
+ onBlur: inputProps.onBlur,
196
+ loading: inputProps.loading,
197
+ fontWeight: inputProps.fontWeight,
198
+ keyboardType: inputProps.keyboardType
199
+ )
200
+ }
201
+ } else {
202
+ Text(title)
203
+ .font(.headline)
204
+ .foregroundColor(tintIconColor)
205
+ .frame(maxWidth: titlePosition == .center ? .infinity : nil, alignment: titlePosition == .center ? .center : .leading)
206
+ }
207
+
208
+ Spacer()
209
+ }
210
+ .frame(height: 52)
211
+ .padding(.horizontal)
212
+
213
+ }
214
+ .background(Color.clear)
215
+ }
216
+ }
217
+ }
218
+
219
+ }
220
+
221
+
222
+
223
+
@@ -0,0 +1,148 @@
1
+ //
2
+ // FloatingButton.swift
3
+ // Pods
4
+ //
5
+ // Created by sophia on 6/2/25.
6
+ //
7
+
8
+ import SwiftUI
9
+ import Combine
10
+
11
+ public enum FABSize {
12
+ case small
13
+ case `default`
14
+ }
15
+
16
+ public enum FABPosition {
17
+ case end
18
+ case center
19
+ }
20
+
21
+ public struct FabProps {
22
+ let icon: String
23
+ let iconColor: Color?
24
+ let label: String?
25
+ let onClick: () -> Void
26
+ let size: FABSize
27
+ let bottom: CGFloat?
28
+ let scrollOffset: CGFloat?
29
+ let position: FABPosition?
30
+
31
+ public init(
32
+ icon: String,
33
+ iconColor: Color? = nil,
34
+ label: String? = nil,
35
+ onClick: @escaping () -> Void,
36
+ size: FABSize = .default,
37
+ bottom: CGFloat? = nil,
38
+ scrollOffset: CGFloat? = nil,
39
+ position: FABPosition? = .end
40
+ ) {
41
+ self.icon = icon
42
+ self.iconColor = iconColor
43
+ self.label = label
44
+ self.onClick = onClick
45
+ self.size = size
46
+ self.bottom = bottom
47
+ self.scrollOffset = scrollOffset
48
+ self.position = position
49
+ }
50
+ }
51
+
52
+ public struct FloatingButton: View {
53
+ @State private var lastScrollOffset: CGFloat = 0
54
+ @State private var isExpanded: Bool = false
55
+ let scrollOffset: CGFloat
56
+ let bottomPadding: CGFloat
57
+ let onClick: () -> Void
58
+ let containerColor: Color
59
+ let contentColor: Color
60
+ let icon: String
61
+ let iconColor: Color?
62
+ let text: String?
63
+ let size: FABSize
64
+ let position: FABPosition
65
+ let keyboardOffset: CGFloat
66
+
67
+ public init(
68
+ scrollOffset: CGFloat = 0,
69
+ bottomPadding: CGFloat = 0,
70
+ onClick: @escaping () -> Void,
71
+ containerColor: Color = .blue,
72
+ contentColor: Color = .white,
73
+ icon: String,
74
+ iconColor: Color? = nil,
75
+ text: String? = nil,
76
+ size: FABSize = .default,
77
+ position: FABPosition = .end,
78
+ keyboardOffset: CGFloat = 0
79
+ ) {
80
+ self.scrollOffset = scrollOffset
81
+ self.bottomPadding = bottomPadding
82
+ self.onClick = onClick
83
+ self.containerColor = containerColor
84
+ self.contentColor = contentColor
85
+ self.icon = icon
86
+ self.iconColor = iconColor
87
+ self.text = text
88
+ self.size = size
89
+ self.position = position
90
+ self.keyboardOffset = keyboardOffset
91
+ }
92
+
93
+ public var body: some View {
94
+ VStack {
95
+ Spacer()
96
+ HStack {
97
+ if position == .center {
98
+ Spacer()
99
+ }
100
+ FloatingButtonContent()
101
+ .padding(.trailing, position == .end ? 12 : 0)
102
+ .padding(.bottom, bottomPadding)
103
+ .offset(y: -keyboardOffset)
104
+ if position == .end {
105
+ Spacer()
106
+ }
107
+ }
108
+ }
109
+ .onReceive(Just(scrollOffset)) { newValue in
110
+ withAnimation(.easeInOut(duration: 0.3)) {
111
+ isExpanded = newValue > lastScrollOffset
112
+ lastScrollOffset = newValue
113
+ }
114
+ }
115
+ }
116
+
117
+ @ViewBuilder
118
+ private func FloatingButtonContent() -> some View {
119
+ SwiftUI.Button(action: onClick) {
120
+ HStack {
121
+ Image(systemName: icon)
122
+ .foregroundColor(iconColor ?? .white)
123
+ .font(size == .small ? .system(size: 12) : .system(size: 24))
124
+
125
+ if isExpanded, let text = text {
126
+ Text(text)
127
+ .foregroundColor(.white)
128
+ .transition(.asymmetric(insertion: expandAnimation, removal: collapseAnimation))
129
+ }
130
+ }
131
+ .padding(.horizontal, isExpanded ? 12 : 0)
132
+ .frame(width: isExpanded ? 80 : (size == .small ? 36 : 48), height: size == .small ? 36 : 48)
133
+ .background(containerColor)
134
+ .cornerRadius(24)
135
+ .shadow(radius: 4)
136
+ }
137
+ }
138
+
139
+ private var expandAnimation: AnyTransition {
140
+ AnyTransition.opacity.animation(.easeIn(duration: 0.2))
141
+ .combined(with: .move(edge: .leading))
142
+ }
143
+
144
+ private var collapseAnimation: AnyTransition {
145
+ AnyTransition.opacity.animation(.easeOut(duration: 0.5))
146
+ .combined(with: .move(edge: .trailing))
147
+ }
148
+ }
@@ -0,0 +1,175 @@
1
+ //
2
+ // Screen.swift
3
+ // Pods
4
+ //
5
+ // Created by sophia on 5/2/25.
6
+ //
7
+
8
+ import SwiftUI
9
+
10
+ public struct Screen<Content: View>: View {
11
+ var backgroundColor: Color?
12
+ var isBack: Bool
13
+ var headerType: HeaderType
14
+ var verticalAlignment: VerticalAlignment
15
+ var horizontalAlignment: HorizontalAlignment
16
+ var title: String
17
+ var titlePosition: TitlePosition
18
+ var goBack: (() -> Void)?
19
+ var scrollable: Bool
20
+ var onContentLayout: ((CGRect) -> Void)?
21
+ var useAvoidKeyboard: Bool
22
+ var footer: (() -> AnyView)?
23
+ var headerRight: (() -> AnyView)?
24
+ var animatedHeader: AnimatedHeader? = nil
25
+ var layoutOffset: CGFloat
26
+ var inputSearchProps: InputSearchProps? = nil
27
+ var fabProps: FabProps? = nil
28
+ var content: () -> Content
29
+
30
+ public init(
31
+ backgroundColor: Color? = nil,
32
+ isBack: Bool = true,
33
+ headerType: HeaderType = .default,
34
+ verticalAlignment: VerticalAlignment = .top,
35
+ horizontalAlignment: HorizontalAlignment = .leading,
36
+ title: String = "Stack",
37
+ titlePosition: TitlePosition = .center,
38
+ goBack: (() -> Void)? = nil,
39
+ scrollable: Bool = true,
40
+ onContentLayout: ((CGRect) -> Void)? = nil,
41
+ useAvoidKeyboard: Bool = true,
42
+ footer: (() -> AnyView)? = nil,
43
+ headerRight: (() -> AnyView)? = nil,
44
+ animatedHeader: AnimatedHeader? = nil,
45
+ layoutOffset: CGFloat = 56,
46
+ inputSearchProps: InputSearchProps? = nil,
47
+ fabProps: FabProps? = nil,
48
+ @ViewBuilder content: @escaping () -> Content
49
+ ) {
50
+ self.backgroundColor = backgroundColor
51
+ self.isBack = isBack
52
+ self.headerType = headerType
53
+ self.verticalAlignment = verticalAlignment
54
+ self.horizontalAlignment = horizontalAlignment
55
+ self.title = title
56
+ self.titlePosition = titlePosition
57
+ self.goBack = goBack
58
+ self.scrollable = scrollable
59
+ self.onContentLayout = onContentLayout
60
+ self.useAvoidKeyboard = useAvoidKeyboard
61
+ self.footer = footer
62
+ self.headerRight = headerRight
63
+ self.animatedHeader = animatedHeader
64
+ self.layoutOffset = layoutOffset
65
+ self.inputSearchProps = inputSearchProps
66
+ self.fabProps = fabProps
67
+ self.content = content
68
+ }
69
+
70
+ @State private var scrollOffset: CGFloat = 0
71
+
72
+ public var body: some View {
73
+ GeometryReader { geometry in
74
+ let safeAreaInsets = geometry.safeAreaInsets
75
+ let statusBarHeight = safeAreaInsets.top
76
+ let keyboardHeight: CGFloat = 0
77
+ let keyboardSize: CGFloat = useAvoidKeyboard ? max(keyboardHeight, 0) : 0
78
+
79
+ ZStack {
80
+ (backgroundColor ?? Color.white).edgesIgnoringSafeArea(.all)
81
+
82
+ VStack(spacing: 0) {
83
+ ZStack {
84
+ if animatedHeader == nil {
85
+ HeaderBackground(headerType: headerType, scrollState: scrollOffset)
86
+ } else {
87
+ Color.white.opacity(Double(min(scrollOffset / 114, 1)))
88
+ .overlay(HeaderBackground(headerType: headerType, scrollState: scrollOffset))
89
+
90
+ }
91
+
92
+ Header(
93
+ headerType: headerType,
94
+ titlePosition: titlePosition,
95
+ title: title,
96
+ headerRight: headerRight,
97
+ goBack: goBack,
98
+ opacity: min(scrollOffset / 114, 1),
99
+ animatedHeader: animatedHeader,
100
+ scrollState: scrollOffset,
101
+ inputSearchProps: inputSearchProps
102
+ ).padding(.bottom, headerType == .extended ? 0 : -safeAreaTopInset())
103
+ }.padding(.top, -safeAreaTopInset())
104
+
105
+
106
+ VStack(alignment: horizontalAlignment, spacing: 0) {
107
+ if animatedHeader != nil {
108
+ Spacer().frame(height: statusBarHeight + 52 + layoutOffset)
109
+ }
110
+
111
+ if scrollable {
112
+ ScrollView(.vertical, showsIndicators: false) {
113
+ VStack {
114
+ content()
115
+ }
116
+ .background(GeometryReader { geo -> Color in
117
+ DispatchQueue.main.async {
118
+ self.scrollOffset = -geo.frame(in: .global).origin.y
119
+ }
120
+ return Color.clear
121
+ })
122
+ }
123
+ } else {
124
+ content()
125
+ }
126
+ }
127
+ .padding(.bottom, keyboardSize)
128
+
129
+
130
+ if let footerView = footer?() {
131
+ ZStack(alignment: .top) {
132
+ Rectangle()
133
+ .fill(Colors.black20)
134
+ .frame(height: 4)
135
+ .shadow(color: Colors.black20.opacity(0.2), radius: 10, x: 0, y: -2)
136
+
137
+ Footer(footerView: footerView, keyboardSize: keyboardSize)
138
+ }
139
+ }
140
+
141
+ if let fabProps = fabProps {
142
+ FloatingButton(
143
+ scrollOffset: scrollOffset,
144
+ bottomPadding: fabProps.bottom ?? 16,
145
+ onClick: fabProps.onClick,
146
+ containerColor: .blue,
147
+ contentColor: .white,
148
+ icon: fabProps.icon,
149
+ iconColor: fabProps.iconColor,
150
+ text: fabProps.label,
151
+ size: fabProps.size,
152
+ position: fabProps.position ?? .end,
153
+ keyboardOffset: keyboardSize
154
+ )
155
+ }
156
+ }
157
+
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ struct Footer: View {
164
+ var footerView: AnyView
165
+ var keyboardSize: CGFloat
166
+
167
+ var body: some View {
168
+ VStack {
169
+ footerView
170
+ }
171
+ .padding(.bottom, keyboardSize)
172
+ .background(Colors.black01)
173
+ }
174
+ }
175
+
@@ -41,7 +41,7 @@ public struct Checkbox: View{
41
41
  .resizable()
42
42
  .foregroundColor(backgroundColor)
43
43
  .background(Colors.black01)
44
- .frame(width: 24, height: 24)
44
+ .frame(width: 20, height: 20)
45
45
  }
46
46
  }
47
47
 
@@ -37,6 +37,62 @@ struct RenderRightIconSearch: View {
37
37
  }
38
38
  }
39
39
 
40
+ public struct InputSearchProps {
41
+ @Binding var text: String
42
+ var buttonText: String = ""
43
+ var showButtonText: Bool = false
44
+ var showBorder: Bool = true
45
+ var placeholder: String = ""
46
+ var onChangeText: (String) -> Void = { _ in }
47
+ var onPressButtonText: () -> Void = {}
48
+ var error: String = ""
49
+ var disabled: Bool = false
50
+ var icon: String = ""
51
+ var iconColor: Color = Colors.text
52
+ var onRightIconPressed: () -> Void = {}
53
+ var onFocus: () -> Void = {}
54
+ var onBlur: () -> Void = {}
55
+ var loading: Bool = false
56
+ var fontWeight: Font.Weight = .regular
57
+ var keyboardType: UIKeyboardType = .default
58
+
59
+ public init(text: Binding<String>,
60
+ buttonText: String = "",
61
+ showButtonText: Bool = false,
62
+ showBorder: Bool = true,
63
+ placeholder: String = "",
64
+ onChangeText: @escaping (String) -> Void = { _ in },
65
+ onPressButtonText: @escaping () -> Void = {},
66
+ error: String = "",
67
+ disabled: Bool = false,
68
+ icon: String = "",
69
+ iconColor: Color = Colors.text,
70
+ onRightIconPressed: @escaping () -> Void = {},
71
+ onFocus: @escaping () -> Void = {},
72
+ onBlur: @escaping () -> Void = {},
73
+ loading: Bool = false,
74
+ fontWeight: Font.Weight = .regular,
75
+ keyboardType: UIKeyboardType = .default) {
76
+ self._text = text
77
+ self.buttonText = buttonText
78
+ self.showButtonText = showButtonText
79
+ self.showBorder = showBorder
80
+ self.placeholder = placeholder
81
+ self.onChangeText = onChangeText
82
+ self.onPressButtonText = onPressButtonText
83
+ self.error = error
84
+ self.disabled = disabled
85
+ self.icon = icon
86
+ self.iconColor = iconColor
87
+ self.onRightIconPressed = onRightIconPressed
88
+ self.onFocus = onFocus
89
+ self.onBlur = onBlur
90
+ self.loading = loading
91
+ self.fontWeight = fontWeight
92
+ self.keyboardType = keyboardType
93
+ }
94
+ }
95
+
40
96
  // MARK: - InputSearch
41
97
 
42
98
  public struct InputSearch: View {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.111.1-rc.2",
3
+ "version": "0.112.1-rc.1",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},