@momo-kits/native-kits 0.162.2-test.23-debug → 0.162.2-test.24-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.
- package/compose/build.gradle.kts +1 -1
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +63 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +32 -19
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +49 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +5 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +4 -0
- package/gradle.properties +1 -1
- package/package.json +1 -1
- package/publish.sh +3 -0
package/compose/build.gradle.kts
CHANGED
|
@@ -129,8 +129,6 @@ actual fun LottieAnimation(
|
|
|
129
129
|
currentOnEvent?.invoke(if (isPlaying) LottieEvent.Start else LottieEvent.Pause)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
// Only fire finish once the animation has actually advanced (armed by a not-at-end frame) then
|
|
133
|
-
// reaches the end, so a transient isAtEnd at init can't produce a spurious callback.
|
|
134
132
|
LaunchedEffect(lottieState) {
|
|
135
133
|
var armed = false
|
|
136
134
|
snapshotFlow { lottieState.isAtEnd }.collect { atEnd ->
|
|
@@ -1,2 +1,65 @@
|
|
|
1
1
|
package vn.momo.kits.layout
|
|
2
2
|
|
|
3
|
+
import androidx.compose.foundation.background
|
|
4
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
5
|
+
import androidx.compose.foundation.layout.Box
|
|
6
|
+
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
7
|
+
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
8
|
+
import androidx.compose.foundation.layout.FlowRow
|
|
9
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
10
|
+
import androidx.compose.foundation.layout.padding
|
|
11
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
12
|
+
import androidx.compose.runtime.Composable
|
|
13
|
+
import androidx.compose.runtime.CompositionLocalProvider
|
|
14
|
+
import androidx.compose.ui.Modifier
|
|
15
|
+
import androidx.compose.ui.draw.clip
|
|
16
|
+
import androidx.compose.ui.draw.shadow
|
|
17
|
+
import androidx.compose.ui.unit.dp
|
|
18
|
+
import vn.momo.kits.components.Image
|
|
19
|
+
import vn.momo.kits.const.AppTheme
|
|
20
|
+
import vn.momo.kits.const.Radius
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A white rounded surface card that lays its [Item]s on a 12-column grid
|
|
24
|
+
* (React kit foundations/Layout/Card). 8dp gutter, 12dp padding, 12dp
|
|
25
|
+
* horizontal margin, Radius.M corners, background = theme surface, optional
|
|
26
|
+
* shadow or [backgroundImage]. Items flow left-to-right and wrap.
|
|
27
|
+
*/
|
|
28
|
+
@OptIn(ExperimentalLayoutApi::class)
|
|
29
|
+
@Composable
|
|
30
|
+
fun Card(
|
|
31
|
+
useShadow: Boolean = false,
|
|
32
|
+
backgroundImage: String? = null,
|
|
33
|
+
modifier: Modifier = Modifier,
|
|
34
|
+
content: @Composable () -> Unit,
|
|
35
|
+
) {
|
|
36
|
+
val columns = 12
|
|
37
|
+
val gutter = 8.dp
|
|
38
|
+
val shape = RoundedCornerShape(Radius.M)
|
|
39
|
+
var surface = modifier.fillMaxWidth().padding(horizontal = 12.dp)
|
|
40
|
+
if (useShadow) surface = surface.shadow(4.dp, shape)
|
|
41
|
+
surface = surface.clip(shape)
|
|
42
|
+
// The React kit drops the surface colour when a backgroundImage is supplied
|
|
43
|
+
// (`!!backgroundImage && { backgroundColor: undefined }`).
|
|
44
|
+
if (backgroundImage == null) surface = surface.background(AppTheme.current.colors.background.surface)
|
|
45
|
+
Box(modifier = surface) {
|
|
46
|
+
// React renders this as an absolutely-filled child BEHIND the content
|
|
47
|
+
// (styles.imageBackground: position absolute, inset 0) — matchParentSize
|
|
48
|
+
// fills the card without contributing to its measured size.
|
|
49
|
+
if (backgroundImage != null) {
|
|
50
|
+
Image(source = backgroundImage, modifier = Modifier.matchParentSize())
|
|
51
|
+
}
|
|
52
|
+
BoxWithConstraints(modifier = Modifier.fillMaxWidth().padding(12.dp)) {
|
|
53
|
+
// `- 1.dp / columns` mirrors the React kit's `- 1 / numberOfColumns`
|
|
54
|
+
// nudge: it keeps a full 12-span Item ~1dp narrower than the content
|
|
55
|
+
// box so sub-pixel rounding can never overflow and wrap the FlowRow.
|
|
56
|
+
val sizePerSpan = (maxWidth - gutter * (columns - 1)) / columns - 1.dp / columns
|
|
57
|
+
CompositionLocalProvider(LocalGridContext provides GridContext(columns, gutter, sizePerSpan)) {
|
|
58
|
+
FlowRow(
|
|
59
|
+
horizontalArrangement = Arrangement.spacedBy(gutter),
|
|
60
|
+
verticalArrangement = Arrangement.spacedBy(gutter),
|
|
61
|
+
) { content() }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -4,32 +4,45 @@ import androidx.compose.foundation.layout.Box
|
|
|
4
4
|
import androidx.compose.foundation.layout.height
|
|
5
5
|
import androidx.compose.foundation.layout.width
|
|
6
6
|
import androidx.compose.runtime.Composable
|
|
7
|
+
import androidx.compose.runtime.compositionLocalOf
|
|
7
8
|
import androidx.compose.ui.Modifier
|
|
8
9
|
import androidx.compose.ui.unit.Dp
|
|
10
|
+
import androidx.compose.ui.unit.dp
|
|
9
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Grid context supplied by [Section] / [Card]: the per-span cell size + gutter,
|
|
14
|
+
* so an [Item] can resolve its pixel width from a 1-12 `widthSpan`. Mirrors the
|
|
15
|
+
* React kit's GridContext (foundations/Layout/GridSystem).
|
|
16
|
+
*/
|
|
10
17
|
data class GridContext(
|
|
11
|
-
val numberOfColumns:
|
|
12
|
-
val
|
|
13
|
-
val sizePerSpan:
|
|
14
|
-
|
|
15
|
-
)
|
|
18
|
+
val numberOfColumns: Int = 12,
|
|
19
|
+
val gutter: Dp = 12.dp,
|
|
20
|
+
val sizePerSpan: Dp = 0.dp,
|
|
21
|
+
) {
|
|
22
|
+
/** Width covering `span` columns + the (span-1) gutters between them. */
|
|
23
|
+
fun sizeForSpan(span: Int): Dp = sizePerSpan * span + gutter * (span - 1)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Provided by Section/Card; null when an Item is rendered outside a grid. */
|
|
27
|
+
val LocalGridContext = compositionLocalOf<GridContext?> { null }
|
|
16
28
|
|
|
29
|
+
/**
|
|
30
|
+
* A grid cell. `widthSpan` (1-12) sets the width as a fraction of the parent
|
|
31
|
+
* Section/Card; the parent's flex-wrap flows the cells into rows. Rendered
|
|
32
|
+
* outside a grid it just wraps its content at its natural size.
|
|
33
|
+
*/
|
|
17
34
|
@Composable
|
|
18
35
|
fun Item(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
content: @Composable () -> Unit,
|
|
36
|
+
widthSpan: Int = 12,
|
|
37
|
+
heightSpan: Int = 0,
|
|
22
38
|
modifier: Modifier = Modifier,
|
|
23
|
-
|
|
39
|
+
content: @Composable () -> Unit,
|
|
24
40
|
) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
modifier = modifier.width(width = Dp(widthItem.toFloat()))
|
|
31
|
-
.height(height = Dp(heightItem.toFloat()))
|
|
32
|
-
) {
|
|
33
|
-
content()
|
|
41
|
+
val grid = LocalGridContext.current
|
|
42
|
+
var m = modifier
|
|
43
|
+
if (grid != null) {
|
|
44
|
+
m = m.width(grid.sizeForSpan(widthSpan))
|
|
45
|
+
if (heightSpan > 0) m = m.height(grid.sizeForSpan(heightSpan))
|
|
34
46
|
}
|
|
35
|
-
}
|
|
47
|
+
Box(modifier = m) { content() }
|
|
48
|
+
}
|
|
@@ -1,2 +1,51 @@
|
|
|
1
1
|
package vn.momo.kits.layout
|
|
2
2
|
|
|
3
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
4
|
+
import androidx.compose.foundation.layout.Box
|
|
5
|
+
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
6
|
+
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
7
|
+
import androidx.compose.foundation.layout.FlowRow
|
|
8
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
9
|
+
import androidx.compose.foundation.layout.padding
|
|
10
|
+
import androidx.compose.runtime.Composable
|
|
11
|
+
import androidx.compose.runtime.CompositionLocalProvider
|
|
12
|
+
import androidx.compose.ui.Modifier
|
|
13
|
+
import androidx.compose.ui.unit.dp
|
|
14
|
+
import vn.momo.kits.components.Image
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A transparent 12-column grid row that wraps its [Item]s (React kit
|
|
18
|
+
* foundations/Layout/Section). 12dp gutter; 12dp horizontal margin when
|
|
19
|
+
* `useMargin`; optional [backgroundImage]. Items flow left-to-right and wrap.
|
|
20
|
+
*/
|
|
21
|
+
@OptIn(ExperimentalLayoutApi::class)
|
|
22
|
+
@Composable
|
|
23
|
+
fun Section(
|
|
24
|
+
useMargin: Boolean = true,
|
|
25
|
+
backgroundImage: String? = null,
|
|
26
|
+
modifier: Modifier = Modifier,
|
|
27
|
+
content: @Composable () -> Unit,
|
|
28
|
+
) {
|
|
29
|
+
val columns = 12
|
|
30
|
+
val gutter = 12.dp
|
|
31
|
+
val margin = if (useMargin) 12.dp else 0.dp
|
|
32
|
+
Box(modifier = modifier.fillMaxWidth().padding(horizontal = margin)) {
|
|
33
|
+
// React renders this as an absolutely-filled child behind the content
|
|
34
|
+
// (styles.imageBackground: position absolute, inset 0).
|
|
35
|
+
if (backgroundImage != null) {
|
|
36
|
+
Image(source = backgroundImage, modifier = Modifier.matchParentSize())
|
|
37
|
+
}
|
|
38
|
+
BoxWithConstraints(modifier = Modifier.fillMaxWidth()) {
|
|
39
|
+
// `- 1.dp / columns` mirrors the React kit's `- 1 / numberOfColumns`
|
|
40
|
+
// nudge — keeps a full 12-span Item ~1dp inside the content box so
|
|
41
|
+
// sub-pixel rounding can never overflow and wrap the FlowRow.
|
|
42
|
+
val sizePerSpan = (maxWidth - gutter * (columns - 1)) / columns - 1.dp / columns
|
|
43
|
+
CompositionLocalProvider(LocalGridContext provides GridContext(columns, gutter, sizePerSpan)) {
|
|
44
|
+
FlowRow(
|
|
45
|
+
horizontalArrangement = Arrangement.spacedBy(gutter),
|
|
46
|
+
verticalArrangement = Arrangement.spacedBy(gutter),
|
|
47
|
+
) { content() }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -24,6 +24,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
24
24
|
import androidx.compose.runtime.Composable
|
|
25
25
|
import androidx.compose.runtime.DisposableEffect
|
|
26
26
|
import androidx.compose.runtime.LaunchedEffect
|
|
27
|
+
import androidx.compose.runtime.mutableStateOf
|
|
27
28
|
import androidx.compose.runtime.remember
|
|
28
29
|
import androidx.compose.runtime.rememberCoroutineScope
|
|
29
30
|
import androidx.compose.ui.Alignment
|
|
@@ -101,7 +102,11 @@ internal fun BottomSheet(
|
|
|
101
102
|
)
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
val isClosing = remember { mutableStateOf(false) }
|
|
106
|
+
|
|
104
107
|
fun closeEvent(){
|
|
108
|
+
if (isClosing.value) return
|
|
109
|
+
isClosing.value = true
|
|
105
110
|
coroutineScope.launch {
|
|
106
111
|
sheetOffset.animateTo(
|
|
107
112
|
targetValue = screenHeightPx,
|
package/gradle.properties
CHANGED
package/package.json
CHANGED
package/publish.sh
CHANGED
|
@@ -251,6 +251,9 @@ phase_publish_maven() {
|
|
|
251
251
|
|
|
252
252
|
# Temporarily remove composeResources and compose { resources { ... } } block
|
|
253
253
|
echo "📦 Backing up sample/shared composeResources and build.gradle.kts..."
|
|
254
|
+
# mv into an existing dir nests instead of renaming, so a backup left behind by a
|
|
255
|
+
# crashed run must be cleared first or the restore below puts back the wrong tree.
|
|
256
|
+
rm -rf sample/shared/src/commonMain/composeResources.backup
|
|
254
257
|
if [ -d "sample/shared/src/commonMain/composeResources" ]; then
|
|
255
258
|
mv sample/shared/src/commonMain/composeResources sample/shared/src/commonMain/composeResources.backup
|
|
256
259
|
fi
|