@momo-kits/native-kits 0.159.1-beta.8-debug → 0.160.1-beta.10-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.
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.159.1-beta.8-debug"
43
+ version = "0.160.1-beta.10-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |spec|
2
2
  spec.name = 'compose'
3
- spec.version = '0.157.1-beta.3'
3
+ spec.version = '0.159.1-beta.12'
4
4
  spec.homepage = 'https://momo.vn'
5
5
  spec.source = { :http=> ''}
6
6
  spec.authors = ''
@@ -10,27 +10,20 @@ Pod::Spec.new do |spec|
10
10
  spec.libraries = 'c++'
11
11
  spec.ios.deployment_target = '15.0'
12
12
  spec.dependency 'lottie-ios', '4.4.3'
13
-
14
13
  if !Dir.exist?('build/cocoapods/framework/kits.framework') || Dir.empty?('build/cocoapods/framework/kits.framework')
15
14
  raise "
16
-
17
15
  Kotlin framework 'kits' doesn't exist yet, so a proper Xcode project can't be generated.
18
16
  'pod install' should be executed after running ':generateDummyFramework' Gradle task:
19
-
20
17
  ./gradlew :compose:generateDummyFramework
21
-
22
18
  Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)"
23
19
  end
24
-
25
20
  spec.xcconfig = {
26
21
  'ENABLE_USER_SCRIPT_SANDBOXING' => 'NO',
27
22
  }
28
-
29
23
  spec.pod_target_xcconfig = {
30
24
  'KOTLIN_PROJECT_PATH' => ':compose',
31
25
  'PRODUCT_MODULE_NAME' => 'kits',
32
26
  }
33
-
34
27
  spec.script_phases = [
35
28
  {
36
29
  :name => 'Build compose',
@@ -38,8 +31,8 @@ Pod::Spec.new do |spec|
38
31
  :shell_path => '/bin/sh',
39
32
  :script => <<-SCRIPT
40
33
  if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then
41
- echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\""
42
- exit 0
34
+ echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\""
35
+ exit 0
43
36
  fi
44
37
  set -ev
45
38
  REPO_ROOT="$PODS_TARGET_SRCROOT"
@@ -51,4 +44,4 @@ Pod::Spec.new do |spec|
51
44
  }
52
45
  ]
53
46
  spec.resources = ['build/compose/cocoapods/compose-resources']
54
- end
47
+ end
@@ -67,16 +67,17 @@ actual fun ProvideNavigationEventDispatcherOwner(content: @Composable () -> Unit
67
67
 
68
68
  @Composable
69
69
  actual fun getScreenHeight(): Dp {
70
- return getScreenDimensions().height.dp + if (getAndroidBuildVersion() >= 35) 0.dp else AppStatusBar.current + AppNavigationBar.current
70
+ return getScreenDimensions().height.dp + if (getOSVersion() >= 35) 0.dp else AppStatusBar.current + AppNavigationBar.current
71
71
  }
72
72
 
73
- actual fun getAndroidBuildVersion(): Int = Build.VERSION.SDK_INT
73
+ actual fun getOSVersion(): OSVersion = OSVersion.Android(sdk = Build.VERSION.SDK_INT)
74
74
 
75
75
  @Composable
76
76
  actual fun LottieAnimation(
77
77
  path: String,
78
78
  tintColor: Color?,
79
79
  bgColor: Color?,
80
+ placedAsOverlay: Boolean,
80
81
  modifier: Modifier
81
82
  ) {
82
83
  val json = readJson(path)
@@ -18,9 +18,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
18
18
  import androidx.compose.foundation.layout.height
19
19
  import androidx.compose.foundation.layout.ime
20
20
  import androidx.compose.foundation.layout.imePadding
21
+ import androidx.compose.foundation.layout.navigationBars
21
22
  import androidx.compose.foundation.layout.offset
22
23
  import androidx.compose.foundation.layout.padding
23
- import androidx.compose.foundation.layout.systemBars
24
24
  import androidx.compose.foundation.rememberScrollState
25
25
  import androidx.compose.foundation.verticalScroll
26
26
  import androidx.compose.runtime.Composable
@@ -43,7 +43,6 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
43
43
  import androidx.compose.ui.unit.Dp
44
44
  import androidx.compose.ui.unit.IntOffset
45
45
  import androidx.compose.ui.unit.dp
46
- import androidx.compose.ui.unit.min
47
46
  import androidx.compose.ui.zIndex
48
47
  import kotlinx.coroutines.CoroutineScope
49
48
  import kotlinx.coroutines.Dispatchers
@@ -60,8 +59,9 @@ import vn.momo.kits.modifier.DeprecatedModifier
60
59
  import vn.momo.kits.modifier.conditional
61
60
  import vn.momo.kits.modifier.shadow
62
61
  import vn.momo.kits.navigation.component.SnackBar
63
- import vn.momo.kits.platform.getAndroidBuildVersion
62
+ import vn.momo.kits.platform.supportsImePadding
64
63
  import vn.momo.kits.utils.getAppStatusBarHeight
64
+ import vn.momo.kits.utils.getNavigationBarHeight
65
65
 
66
66
  enum class HeaderType {
67
67
  DEFAULT,
@@ -103,8 +103,8 @@ fun Screen(
103
103
  val keyboardController = LocalSoftwareKeyboardController.current
104
104
 
105
105
  val isKeyboardVisible = isKeyboardVisible()
106
- val indicator = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
107
- val bottomPadding = min(indicator, if (isKeyboardVisible) 0.dp else 21.dp)
106
+ val indicator = getNavigationBarHeight()
107
+ val bottomPadding = if (isKeyboardVisible) 0.dp else indicator
108
108
 
109
109
  val headerHeight = if (animatedHeader !== null)
110
110
  with(LocalDensity.current) { layoutOffset.roundToPx() }
@@ -135,7 +135,7 @@ fun Screen(
135
135
  Box(
136
136
  Modifier.fillMaxSize()
137
137
  .background(backgroundColor ?: AppTheme.current.colors.background.default)
138
- .conditional(useAvoidKeyboard && getAndroidBuildVersion() > 29) {
138
+ .conditional(useAvoidKeyboard && supportsImePadding()) {
139
139
  imePadding()
140
140
  }.then(DeprecatedModifier())
141
141
  ) {
@@ -343,7 +343,7 @@ fun ScreenSnackBarHost(footerHeightPx: Int) {
343
343
  footerHeightPx
344
344
  } else {
345
345
  with(density) {
346
- min(navigationBar, 21.dp).toPx()
346
+ navigationBar.toPx()
347
347
  }
348
348
  }.toInt()
349
349
 
@@ -401,5 +401,3 @@ fun ScreenSnackBarHost(footerHeightPx: Int) {
401
401
 
402
402
 
403
403
 
404
-
405
-
@@ -221,6 +221,7 @@ fun Input(
221
221
  onBlur: () -> Unit = {},
222
222
  loading: Boolean = false,
223
223
  required: Boolean = false,
224
+ maxLength: Int? = null,
224
225
  fontWeight: InputFontWeight = InputFontWeight.REGULAR,
225
226
  keyboardType: KeyboardType = KeyboardType.Text,
226
227
  modifier: Modifier = Modifier,
@@ -319,7 +320,10 @@ fun Input(
319
320
  onBlur()
320
321
  }
321
322
  },
322
- onValueChange = onChangeText,
323
+ onValueChange = { newText ->
324
+ val limitedText = maxLength?.let { newText.take(it) } ?: newText
325
+ onChangeText(limitedText)
326
+ },
323
327
  decorationBox = { innerTextField ->
324
328
  // Floating label
325
329
  if (floatingValue.isNotEmpty() || floatingIcon.isNotEmpty()) {
@@ -8,6 +8,7 @@ import androidx.compose.animation.core.rememberInfiniteTransition
8
8
  import androidx.compose.animation.core.tween
9
9
  import androidx.compose.foundation.background
10
10
  import androidx.compose.foundation.border
11
+ import androidx.compose.ui.draw.alpha
11
12
  import androidx.compose.foundation.clickable
12
13
  import androidx.compose.foundation.layout.Arrangement
13
14
  import androidx.compose.foundation.layout.Box
@@ -129,8 +130,11 @@ fun InputOTP(
129
130
  if (!it.isFocused && isBlurred) onBlur()
130
131
  if (it.isFocused && !isBlurred) isBlurred = true
131
132
  },
132
- decorationBox = { _ ->
133
+ decorationBox = { innerTextField ->
133
134
  Box {
135
+ Box(
136
+ modifier = Modifier.fillMaxWidth().height(56.dp).alpha(0f)
137
+ ) { innerTextField() }
134
138
  if (floatingValue.isNotEmpty()) {
135
139
  Box(
136
140
  modifier = Modifier.wrapContentSize()
@@ -105,6 +105,8 @@ data class InputSearchProps(
105
105
  val iconModifier: Modifier = Modifier,
106
106
  val onClearPress: () -> Unit = {},
107
107
  val leftPosition: Dp? = null,
108
+ val placeholderCustomRender: (@Composable () -> Unit)? = null,
109
+ val searchIcon: (@Composable () -> Unit)? = null
108
110
  )
109
111
 
110
112
  @Composable
@@ -145,12 +147,13 @@ fun InputSearch(
145
147
  )
146
148
  }
147
149
 
148
- Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier
149
- .fillMaxWidth()
150
- .height(36.dp)
151
- .conditional(IsShowBaseLineDebug) {
152
- border(1.dp, Colors.blue_03)
153
- }
150
+ Row(
151
+ verticalAlignment = Alignment.CenterVertically, modifier = Modifier
152
+ .fillMaxWidth()
153
+ .height(36.dp)
154
+ .conditional(IsShowBaseLineDebug) {
155
+ border(1.dp, Colors.blue_03)
156
+ }
154
157
  ) {
155
158
  BasicTextField(
156
159
  enabled = !inputSearchProps.disabled,
@@ -184,13 +187,14 @@ fun InputSearch(
184
187
  horizontalArrangement = Arrangement.Start,
185
188
  verticalAlignment = Alignment.CenterVertically
186
189
  ) {
190
+
187
191
  Row(
188
192
  modifier = Modifier.padding(
189
193
  horizontal = Spacing.M
190
194
  ),
191
195
  verticalAlignment = Alignment.CenterVertically
192
196
  ) {
193
- Icon(
197
+ inputSearchProps.searchIcon?.invoke() ?: Icon(
194
198
  source = "navigation_search",
195
199
  modifier = Modifier.padding(end = Spacing.XS),
196
200
  size = 24.dp,
@@ -198,13 +202,14 @@ fun InputSearch(
198
202
  )
199
203
  Box(Modifier.weight(1f)) {
200
204
  if (inputSearchProps.text.value.isEmpty()) {
201
- Text(
202
- text = inputSearchProps.placeholder,
203
- style = placeHolderStyle,
204
- maxLines = 1,
205
- color = placeholderColor,
206
- overflow = TextOverflow.Ellipsis
207
- )
205
+ inputSearchProps.placeholderCustomRender?.invoke()
206
+ ?: Text(
207
+ text = inputSearchProps.placeholder,
208
+ style = placeHolderStyle,
209
+ maxLines = 1,
210
+ color = placeholderColor,
211
+ overflow = TextOverflow.Ellipsis
212
+ )
208
213
  }
209
214
  innerTextField()
210
215
  }
@@ -33,7 +33,7 @@ import kotlin.math.max
33
33
  import kotlin.math.min
34
34
 
35
35
  const val DEFAULT_SCREEN_SIZE = 375f
36
- const val MAX_FONT_SCALE = 1.2f
36
+ const val MAX_FONT_SCALE = 1.5f
37
37
  const val MAX_DEVICE_SCALE = 5
38
38
 
39
39
  @Composable
@@ -1,41 +1,18 @@
1
1
  package vn.momo.kits.navigation
2
2
 
3
+ import androidx.compose.animation.*
3
4
  import androidx.compose.animation.core.tween
4
- import androidx.compose.animation.fadeIn
5
- import androidx.compose.animation.slideInHorizontally
6
- import androidx.compose.animation.slideInVertically
7
- import androidx.compose.animation.slideOutHorizontally
8
- import androidx.compose.animation.slideOutVertically
9
- import androidx.compose.foundation.layout.WindowInsets
10
- import androidx.compose.foundation.layout.asPaddingValues
11
- import androidx.compose.foundation.layout.systemBars
12
- import androidx.compose.runtime.Composable
13
- import androidx.compose.runtime.CompositionLocalProvider
14
- import androidx.compose.runtime.DisposableEffect
15
- import androidx.compose.runtime.LaunchedEffect
16
- import androidx.compose.runtime.mutableStateOf
17
- import androidx.compose.runtime.remember
18
- import androidx.compose.runtime.staticCompositionLocalOf
5
+ import androidx.compose.runtime.*
19
6
  import androidx.compose.ui.unit.Dp
20
- import androidx.compose.ui.unit.dp
21
7
  import androidx.navigation.compose.NavHost
22
8
  import androidx.navigation.compose.composable
23
9
  import androidx.navigation.compose.rememberNavController
24
10
  import androidx.navigation.toRoute
25
- import vn.momo.kits.application.AppConfig
26
- import vn.momo.kits.application.AppLanguage
27
- import vn.momo.kits.application.ApplicationContext
28
- import vn.momo.kits.application.KitConfig
29
- import vn.momo.kits.application.MiniAppContext
30
- import vn.momo.kits.application.ScaleSizeMaxRate
31
- import vn.momo.kits.const.AppNavigationBar
32
- import vn.momo.kits.const.AppStatusBar
33
- import vn.momo.kits.const.AppTheme
34
- import vn.momo.kits.const.Theme
35
- import vn.momo.kits.const.ThemeAssets
36
- import vn.momo.kits.const.defaultTheme
11
+ import vn.momo.kits.application.*
12
+ import vn.momo.kits.const.*
37
13
  import vn.momo.kits.platform.ProvideNavigationEventDispatcherOwner
38
14
  import vn.momo.kits.utils.getAppStatusBarHeight
15
+ import vn.momo.kits.utils.getNavigationBarHeight
39
16
  import vn.momo.maxapi.IMaxApi
40
17
 
41
18
  @Composable
@@ -54,11 +31,7 @@ fun NavigationContainer(
54
31
  val navController = rememberNavController()
55
32
  val navigator = remember { Navigator(navController = navController, maxApi = maxApi) }
56
33
  val statusBarHeight = statusBarHeight ?: getAppStatusBarHeight()
57
- val navigationBarHeight = if (AppNavigationBar.current == 0.dp) {
58
- WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
59
- } else {
60
- AppNavigationBar.current
61
- }
34
+ val navigationBarHeight = getNavigationBarHeight()
62
35
 
63
36
  val parentContext = ApplicationContext.current
64
37
  val mergedContext = MiniAppContext.merge(parentContext, applicationContext)
@@ -62,7 +62,7 @@ import vn.momo.kits.navigation.component.HeaderRight
62
62
  import vn.momo.kits.navigation.component.HeaderType
63
63
  import vn.momo.kits.navigation.component.InputSearchType
64
64
  import vn.momo.kits.platform.BackHandler
65
- import vn.momo.kits.platform.getAndroidBuildVersion
65
+ import vn.momo.kits.platform.supportsImePadding
66
66
  import vn.momo.kits.navigation.tracking.ScreenTracker
67
67
  import vn.momo.kits.navigation.tracking.ScreenTrackingState
68
68
  import kotlinx.coroutines.delay
@@ -166,7 +166,7 @@ internal fun StackScreen(
166
166
  .conditional(options.keyboardOptions.keyboardShouldPersistTaps) {
167
167
  hideKeyboardOnTap()
168
168
  }
169
- .conditional(options.keyboardOptions.useAvoidKeyboard && getAndroidBuildVersion() > 29) {
169
+ .conditional(options.keyboardOptions.useAvoidKeyboard && supportsImePadding()) {
170
170
  imePadding()
171
171
  }
172
172
  ) {
@@ -289,7 +289,7 @@ fun FooterContent(){
289
289
  val imeBottom = ime.getBottom(density)
290
290
  val thresholdPx = with(density) { 50.dp.toPx() }
291
291
  val isKeyboardVisible = imeBottom > thresholdPx
292
- val bottomPadding = min(AppNavigationBar.current, if (isKeyboardVisible) 0.dp else 21.dp)
292
+ val bottomPadding = if (isKeyboardVisible) 0.dp else AppNavigationBar.current
293
293
  Footer(footerComponent = options.footerComponent, bottomPadding = bottomPadding)
294
294
  }
295
295
  }
@@ -18,7 +18,6 @@ import androidx.compose.runtime.LaunchedEffect
18
18
  import androidx.compose.ui.Alignment
19
19
  import androidx.compose.ui.Modifier
20
20
  import androidx.compose.ui.unit.dp
21
- import androidx.compose.ui.unit.min
22
21
  import androidx.navigation.compose.NavHost
23
22
  import androidx.navigation.compose.composable
24
23
  import androidx.navigation.compose.rememberNavController
@@ -139,7 +138,7 @@ fun BottomTab(
139
138
  }
140
139
  }
141
140
  )
142
- Spacer(modifier = Modifier.fillMaxWidth().height(min(AppNavigationBar.current, 21.dp) + Spacing.S).background(AppTheme.current.colors.background.surface))
141
+ Spacer(modifier = Modifier.fillMaxWidth().height(AppNavigationBar.current + Spacing.S).background(AppTheme.current.colors.background.surface))
143
142
  }
144
143
  }
145
144
  }
@@ -19,7 +19,6 @@ import androidx.compose.ui.layout.onGloballyPositioned
19
19
  import androidx.compose.ui.platform.LocalDensity
20
20
  import androidx.compose.ui.unit.IntOffset
21
21
  import androidx.compose.ui.unit.dp
22
- import androidx.compose.ui.unit.min
23
22
  import kotlinx.coroutines.delay
24
23
  import vn.momo.kits.application.IsShowBaseLineDebug
25
24
  import vn.momo.kits.const.Colors
@@ -56,7 +55,7 @@ fun SnackBar(
56
55
  val footerHeight = if (options.footerComponent != null) {
57
56
  footerHeightPxState.value
58
57
  } else {
59
- with(density){ min(navigationBar, 21.dp).toPx() }
58
+ with(density){ navigationBar.toPx() }
60
59
  }.toInt()
61
60
 
62
61
  var startPosition by remember { mutableStateOf(Float.MAX_VALUE) }
@@ -129,4 +128,4 @@ fun SnackBar(
129
128
  is SnackBar.Toast -> {}
130
129
  }
131
130
  }
132
- }
131
+ }
@@ -30,13 +30,26 @@ expect fun ProvideNavigationEventDispatcherOwner(content: @Composable () -> Unit
30
30
  @Composable
31
31
  expect fun getScreenHeight(): Dp
32
32
 
33
- expect fun getAndroidBuildVersion(): Int
33
+ sealed interface OSVersion {
34
+ val value: Int
35
+ data class Android(val sdk: Int) : OSVersion { override val value: Int get() = sdk }
36
+ data class IOS(val major: Int) : OSVersion { override val value: Int get() = major }
37
+
38
+ operator fun compareTo(other: Int): Int = value.compareTo(other)
39
+ }
40
+ expect fun getOSVersion(): OSVersion
41
+
42
+ fun supportsImePadding(): Boolean = when (val v = getOSVersion()) {
43
+ is OSVersion.Android -> v.sdk > 29
44
+ is OSVersion.IOS -> true
45
+ }
34
46
 
35
47
  @Composable
36
48
  expect fun LottieAnimation(
37
49
  path: String,
38
50
  tintColor: Color? = null,
39
51
  bgColor: Color? = null,
52
+ placedAsOverlay: Boolean = false,
40
53
  modifier: Modifier = Modifier
41
54
  )
42
55
 
@@ -12,7 +12,10 @@ import androidx.compose.ui.graphics.Color
12
12
  import androidx.compose.ui.platform.LocalDensity
13
13
  import androidx.compose.ui.unit.Dp
14
14
  import androidx.compose.ui.unit.dp
15
+ import androidx.compose.ui.unit.min
16
+ import vn.momo.kits.const.AppNavigationBar
15
17
  import vn.momo.kits.const.AppStatusBar
18
+ import vn.momo.kits.platform.getPlatformName
16
19
  import kotlin.math.abs
17
20
 
18
21
 
@@ -86,3 +89,17 @@ fun getAppStatusBarHeight(): Dp {
86
89
  AppStatusBar.current
87
90
  }
88
91
  }
92
+
93
+ @Composable
94
+ fun getNavigationBarHeight(): Dp {
95
+ return if (AppNavigationBar.current == 0.dp) {
96
+ val systemBottomPadding = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
97
+ if (getPlatformName() == "iOS") {
98
+ min(systemBottomPadding, 21.dp)
99
+ } else {
100
+ systemBottomPadding
101
+ }
102
+ } else {
103
+ AppNavigationBar.current
104
+ }
105
+ }
@@ -12,17 +12,19 @@ import androidx.compose.runtime.getValue
12
12
  import androidx.compose.runtime.mutableStateOf
13
13
  import androidx.compose.runtime.remember
14
14
  import androidx.compose.runtime.setValue
15
+ import androidx.compose.ui.ExperimentalComposeUiApi
15
16
  import androidx.compose.ui.InternalComposeUiApi
16
17
  import androidx.compose.ui.Modifier
17
18
  import androidx.compose.ui.backhandler.LocalCompatNavigationEventDispatcherOwner
18
19
  import androidx.compose.ui.graphics.Color
19
20
  import androidx.compose.ui.graphics.NativePaint
20
21
  import androidx.compose.ui.graphics.toArgb
21
- import androidx.compose.ui.interop.UIKitView
22
22
  import androidx.compose.ui.semantics.SemanticsPropertyKey
23
23
  import androidx.compose.ui.semantics.semantics
24
24
  import androidx.compose.ui.unit.Dp
25
25
  import androidx.compose.ui.unit.dp
26
+ import androidx.compose.ui.viewinterop.UIKitInteropProperties
27
+ import androidx.compose.ui.viewinterop.UIKitView
26
28
  import cocoapods.lottie_ios.CompatibleAnimation
27
29
  import cocoapods.lottie_ios.CompatibleAnimationKeypath
28
30
  import cocoapods.lottie_ios.CompatibleAnimationView
@@ -35,6 +37,7 @@ import org.jetbrains.skia.FilterBlurMode
35
37
  import org.jetbrains.skia.MaskFilter
36
38
  import platform.Foundation.NSBundle
37
39
  import platform.UIKit.UIColor
40
+ import platform.UIKit.UIDevice
38
41
  import platform.UIKit.UIScreen
39
42
 
40
43
  actual fun getPlatformName(): String = "iOS"
@@ -84,14 +87,17 @@ actual fun getScreenHeight(): Dp {
84
87
  return getScreenDimensions().height.dp
85
88
  }
86
89
 
87
- actual fun getAndroidBuildVersion(): Int = 999
90
+ actual fun getOSVersion(): OSVersion = OSVersion.IOS(
91
+ major = UIDevice.currentDevice.systemVersion.substringBefore(".").toIntOrNull() ?: 0
92
+ )
88
93
 
89
- @OptIn(ExperimentalForeignApi::class)
94
+ @OptIn(ExperimentalForeignApi::class, ExperimentalComposeUiApi::class)
90
95
  @Composable
91
96
  actual fun LottieAnimation(
92
97
  path: String,
93
98
  tintColor: Color?,
94
99
  bgColor: Color?,
100
+ placedAsOverlay: Boolean,
95
101
  modifier: Modifier
96
102
  ) {
97
103
  var animation by remember { mutableStateOf<CompatibleAnimation?>(null) }
@@ -109,11 +115,12 @@ actual fun LottieAnimation(
109
115
  Box(modifier) {
110
116
  UIKitView(
111
117
  modifier = Modifier.fillMaxSize(),
118
+ properties = UIKitInteropProperties(placedAsOverlay = placedAsOverlay),
112
119
  factory = {
113
120
  CompatibleAnimationView(value).apply {
114
121
  translatesAutoresizingMaskIntoConstraints = true
115
122
 
116
- setBackgroundColor(bgColor?.toUIColor() ?: UIColor.whiteColor)
123
+ setBackgroundColor(bgColor?.toUIColor() ?: UIColor.clearColor)
117
124
 
118
125
  setLoopAnimationCount(-1.0)
119
126
  setAnimationSpeed(1.0)
@@ -134,7 +141,7 @@ actual fun LottieAnimation(
134
141
  },
135
142
 
136
143
  update = { view ->
137
- view.setBackgroundColor(bgColor?.toUIColor() ?: UIColor.whiteColor)
144
+ view.setBackgroundColor(bgColor?.toUIColor() ?: UIColor.clearColor)
138
145
 
139
146
  if (tintColor != null) {
140
147
  val uiColor = tintColor.toUIColor()
package/gradle.properties CHANGED
@@ -18,7 +18,7 @@ kotlin.apple.xcodeCompatibility.nowarn=true
18
18
  name="ComposeKits"
19
19
  group=vn.momo.kits
20
20
  artifact.id=kits
21
- version=0.159.1-beta.8
21
+ version=0.159.1-beta.16
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
@@ -22,6 +22,7 @@ public struct Input: View {
22
22
  public var leadingIconColor: Color
23
23
  public var loading: Bool
24
24
  public var required: Bool
25
+ public var maxLength: Int?
25
26
  public var fontWeight: InputFontWeight
26
27
  public var keyboardType: UIKeyboardType
27
28
  public var autofocus: Bool
@@ -52,6 +53,7 @@ public struct Input: View {
52
53
  leadingIconColor: Color = Colors.black12,
53
54
  loading: Bool = false,
54
55
  required: Bool = false,
56
+ maxLength: Int? = nil,
55
57
  fontWeight: InputFontWeight = .regular,
56
58
  keyboardType: UIKeyboardType = .default,
57
59
  autofocus: Bool = false,
@@ -78,6 +80,7 @@ public struct Input: View {
78
80
  self.leadingIconColor = leadingIconColor
79
81
  self.loading = loading
80
82
  self.required = required
83
+ self.maxLength = maxLength
81
84
  self.fontWeight = fontWeight
82
85
  self.keyboardType = keyboardType
83
86
  self.autofocus = autofocus
@@ -93,10 +96,10 @@ public struct Input: View {
93
96
  get: { self.text },
94
97
  set: { newValue in
95
98
  self.text = newValue
96
- self.onChangeText?(newValue)
99
+ self.onChangeText?(limitText(newValue))
97
100
  }
98
101
  )
99
-
102
+
100
103
  VStack(alignment: .leading, spacing: 4) {
101
104
  ZStack(alignment: .topLeading) {
102
105
  // Floating label
@@ -142,6 +145,7 @@ public struct Input: View {
142
145
  fontWeight: fontWeight == .bold ? .bold : .regular,
143
146
  textColor: UIColor(getTextColor()),
144
147
  isDisabled: disabled || readOnly,
148
+ maxLength: maxLength,
145
149
  onFocusChange: { focused in
146
150
  handleFocusChange(focused)
147
151
  },
@@ -156,6 +160,12 @@ public struct Input: View {
156
160
  .foregroundColor(getTextColor())
157
161
  .disabled(disabled || readOnly)
158
162
  .applyPrimaryCursorColor()
163
+ .onChange(of: text) { newValue in
164
+ let limited = limitText(newValue)
165
+ if limited != newValue {
166
+ text = limited
167
+ }
168
+ }
159
169
  }
160
170
  }
161
171
 
@@ -239,6 +249,13 @@ public struct Input: View {
239
249
  isPasswordHidden.toggle()
240
250
  onRightIconPressed?()
241
251
  }
252
+
253
+ private func limitText(_ value: String) -> String {
254
+ guard let maxLength = maxLength else {
255
+ return value
256
+ }
257
+ return String(value.prefix(maxLength))
258
+ }
242
259
 
243
260
  private func borderColor() -> Color {
244
261
  if disabled {
@@ -279,6 +296,7 @@ private struct SecureInputField: UIViewRepresentable {
279
296
  var fontWeight: UIFont.Weight
280
297
  var textColor: UIColor
281
298
  var isDisabled: Bool
299
+ var maxLength: Int?
282
300
  var onFocusChange: (Bool) -> Void
283
301
  var onChangeText: ((String) -> Void)?
284
302
 
@@ -307,6 +325,7 @@ private struct SecureInputField: UIViewRepresentable {
307
325
  }
308
326
 
309
327
  func updateUIView(_ textField: UITextField, context: Context) {
328
+ context.coordinator.parent = self
310
329
  if textField.text != text {
311
330
  textField.text = text
312
331
  }
@@ -342,7 +361,7 @@ private struct SecureInputField: UIViewRepresentable {
342
361
  }
343
362
 
344
363
  func textFieldDidEndEditing(_ textField: UITextField) {
345
- parent.text = textField.text ?? ""
364
+ parent.text = limitText(textField.text ?? "")
346
365
  parent.onFocusChange(false)
347
366
  }
348
367
 
@@ -357,7 +376,10 @@ private struct SecureInputField: UIViewRepresentable {
357
376
 
358
377
  @objc func textFieldDidChange(_ textField: UITextField) {
359
378
  if isResettingText { return }
360
- let newText = textField.text ?? ""
379
+ let newText = limitText(textField.text ?? "")
380
+ if textField.text != newText {
381
+ textField.text = newText
382
+ }
361
383
  parent.text = newText
362
384
  parent.onChangeText?(newText)
363
385
  }
@@ -366,6 +388,13 @@ private struct SecureInputField: UIViewRepresentable {
366
388
  textField.resignFirstResponder()
367
389
  return true
368
390
  }
391
+
392
+ private func limitText(_ value: String) -> String {
393
+ guard let maxLength = parent.maxLength else {
394
+ return value
395
+ }
396
+ return String(value.prefix(maxLength))
397
+ }
369
398
  }
370
399
  }
371
400
 
@@ -2,7 +2,7 @@ import SwiftUI
2
2
 
3
3
  public func scaleSize(_ size: CGFloat, _ scaleRate: CGFloat? = nil) -> CGFloat {
4
4
  let defaultScreenSize: CGFloat = 375
5
- let maxFontScale: CGFloat = scaleRate ?? 1.2
5
+ let maxFontScale: CGFloat = scaleRate ?? 1.5
6
6
  let maxDeviceScale: CGFloat = 5
7
7
 
8
8
  let deviceWidth = UIScreen.main.bounds.width
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.159.1-beta.8-debug",
3
+ "version": "0.160.1-beta.10-debug",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},