diff --git a/catalog/src/main/java/kiwi/orbit/compose/catalog/screens/CollapseScreen.kt b/catalog/src/main/java/kiwi/orbit/compose/catalog/screens/CollapseScreen.kt index a5393072a..f05f168b8 100644 --- a/catalog/src/main/java/kiwi/orbit/compose/catalog/screens/CollapseScreen.kt +++ b/catalog/src/main/java/kiwi/orbit/compose/catalog/screens/CollapseScreen.kt @@ -49,7 +49,7 @@ private fun CollapseScreenInner() { Column(modifier = Modifier.padding(16.dp)) { Collapse( expanded = isFirstCollapseExpanded, - onExpandClick = { isFirstCollapseExpanded = it }, + onExpandChange = { isFirstCollapseExpanded = it }, title = { Text(text = "Title 1") }, @@ -60,7 +60,7 @@ private fun CollapseScreenInner() { Collapse( expanded = isSecondCollapseExpanded, - onExpandClick = { isSecondCollapseExpanded = it }, + onExpandChange = { isSecondCollapseExpanded = it }, withSeparator = false, title = { Text(text = "Title 2") diff --git a/docs/03-components/07-interaction/collapse.mdx b/docs/03-components/07-interaction/collapse.mdx index b87396be5..658bda869 100644 --- a/docs/03-components/07-interaction/collapse.mdx +++ b/docs/03-components/07-interaction/collapse.mdx @@ -23,7 +23,7 @@ fun Example() { expanded = expanded, onExpandClick = { expanded = it }, title = { - Text(text = "This the title") + Text(text = "Collapse title") }, content = { Text(text = "This is the collapsible content") @@ -43,7 +43,7 @@ fun Example() { expanded = expanded, onExpandClick = { expanded = it }, title = { - Text(text = "This the title") + Text(text = "Collapse title") }, content = { Text(text = "This is the collapsible content") @@ -64,7 +64,7 @@ composeTestRule.setContent { expanded = expanded, onExpandClick = { expanded = it }, title = { - Text(text = "This the title", modifier = Modifier.testTag("title")) + Text(text = "Collapse title", modifier = Modifier.testTag("title")) }, content = { Text(text = "This is the collapsible content", modifier = Modifier.testTag("content")) @@ -73,7 +73,7 @@ composeTestRule.setContent { ) } -composeTestRule.onNodeWithTag("title").assertIsDisplayed() +composeTestRule.onNodeWithTag("title", useUnmergedTree = true).assertIsDisplayed() composeTestRule.onNodeWithTag("content").assertDoesNotExist() composeTestRule.onNodeWithTag("collapse").performSemanticsAction(SemanticsActions.Expand) diff --git a/ui/src/main/java/kiwi/orbit/compose/ui/controls/Collapse.kt b/ui/src/main/java/kiwi/orbit/compose/ui/controls/Collapse.kt index d479b0f8d..57f7ff13d 100644 --- a/ui/src/main/java/kiwi/orbit/compose/ui/controls/Collapse.kt +++ b/ui/src/main/java/kiwi/orbit/compose/ui/controls/Collapse.kt @@ -2,67 +2,70 @@ package kiwi.orbit.compose.ui.controls import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.material3.Divider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate -import androidx.compose.ui.semantics.AccessibilityAction -import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.semantics.collapse +import androidx.compose.ui.semantics.expand import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import kiwi.orbit.compose.icons.Icons +import kiwi.orbit.compose.ui.OrbitTheme import kiwi.orbit.compose.ui.controls.internal.OrbitPreviews import kiwi.orbit.compose.ui.controls.internal.Preview +import kiwi.orbit.compose.ui.foundation.ProvideMergedTextStyle /** * Hides long or complex information under a block that can be hidden. * * Example : - * - * var expanded by remember { mutableStateOf(false) } - * + * ``` + * var expanded by rememberSaveable { mutableStateOf(false) } * Collapse( * expanded = expanded, * onExpandClick = { expanded = it }, - * title = { - * Text(text = "This the title") - * }, - * content = { - * Text(text = "This is the collapsible content") - * }, + * title = { Text("Title") }, + * content = { Text(text = "This is the collapsible content") }, * ) + * ``` */ @Composable public fun Collapse( expanded: Boolean, - onExpandClick: (Boolean) -> Unit, + onExpandChange: (Boolean) -> Unit, title: @Composable () -> Unit, content: @Composable () -> Unit, modifier: Modifier = Modifier, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, withSeparator: Boolean = true, ) { Column( modifier = modifier.semantics { - this[SemanticsActions.Expand] = AccessibilityAction(SemanticsActions.Expand.name) { + expand { if (!expanded) { - onExpandClick(true) + onExpandChange(true) true } else { false } } - this[SemanticsActions.Collapse] = AccessibilityAction(SemanticsActions.Collapse.name) { + collapse { if (expanded) { - onExpandClick(false) + onExpandChange(false) true } else { false @@ -72,17 +75,33 @@ public fun Collapse( verticalArrangement = Arrangement.spacedBy(8.dp), ) { Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .clickable( + enabled = true, + onClick = { onExpandChange(!expanded) }, + indication = null, + interactionSource = interactionSource, + ) + .padding(vertical = 12.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, ) { - title() - CollapseArrow(expanded = expanded, onClick = { onExpandClick(!expanded) }) + ProvideMergedTextStyle(OrbitTheme.typography.bodyNormalMedium) { + Box(Modifier.weight(1f)) { + title() + } + } + CollapseArrow( + expanded = expanded, + interactionSource = interactionSource, + onClick = { onExpandChange(!expanded) }, + ) } - AnimatedVisibility(visible = expanded, modifier = Modifier.fillMaxWidth()) { - content() + AnimatedVisibility(visible = expanded) { + ProvideMergedTextStyle(OrbitTheme.typography.bodyNormal) { + content() + } } - if (withSeparator) { Divider() } @@ -92,16 +111,17 @@ public fun Collapse( @Composable private fun CollapseArrow( expanded: Boolean, + interactionSource: MutableInteractionSource, onClick: () -> Unit, ) { val arrowRotationDegree by animateFloatAsState( targetValue = if (expanded) 180f else 0f, ) - IconButton( onClick = onClick, - modifier = Modifier - .rotate(arrowRotationDegree), + modifier = Modifier.rotate(arrowRotationDegree), + interactionSource = interactionSource, + minimumInteractiveComponentEnforcement = false, ) { Icon( painter = Icons.ChevronDown, @@ -113,13 +133,13 @@ private fun CollapseArrow( @OrbitPreviews @Composable internal fun CollapsePreview() { - var expanded by remember { mutableStateOf(true) } + var expanded by rememberSaveable { mutableStateOf(true) } Preview { Collapse( expanded = expanded, - onExpandClick = { expanded = it }, + onExpandChange = { expanded = it }, title = { - Text(text = "This the title") + Text(text = "Collapse title") }, content = { Text(text = "This is the collapsible content") diff --git a/ui/src/main/java/kiwi/orbit/compose/ui/controls/IconButton.kt b/ui/src/main/java/kiwi/orbit/compose/ui/controls/IconButton.kt index 90acbb8ca..7739d1b4c 100644 --- a/ui/src/main/java/kiwi/orbit/compose/ui/controls/IconButton.kt +++ b/ui/src/main/java/kiwi/orbit/compose/ui/controls/IconButton.kt @@ -22,6 +22,7 @@ public fun IconButton( modifier: Modifier = Modifier, enabled: Boolean = true, rippleRadius: Dp = RippleRadius, + minimumInteractiveComponentEnforcement: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, content: @Composable () -> Unit, ) { @@ -34,7 +35,13 @@ public fun IconButton( interactionSource = interactionSource, indication = rememberRipple(bounded = false, radius = rippleRadius), ) - .size(rippleRadius * 2), + .run { + if (minimumInteractiveComponentEnforcement) { + size(rippleRadius * 2) + } else { + this + } + }, contentAlignment = Alignment.Center, ) { val contentEmphasis = if (enabled) LocalContentEmphasis.current else ContentEmphasis.Disabled diff --git a/ui/src/test/kotlin/kiwi/orbit/compose/ui/controls/CollapseTest.kt b/ui/src/test/kotlin/kiwi/orbit/compose/ui/controls/CollapseTest.kt index 2221d6fc8..7e9367dcf 100644 --- a/ui/src/test/kotlin/kiwi/orbit/compose/ui/controls/CollapseTest.kt +++ b/ui/src/test/kotlin/kiwi/orbit/compose/ui/controls/CollapseTest.kt @@ -27,9 +27,9 @@ internal class CollapseTest { var expanded by remember { mutableStateOf(false) } Collapse( expanded = expanded, - onExpandClick = { expanded = it }, + onExpandChange = { expanded = it }, title = { - Text(text = "This the title", modifier = Modifier.testTag("title")) + Text(text = "Collapse title", modifier = Modifier.testTag("title")) }, content = { Text(text = "This is the collapsible content", modifier = Modifier.testTag("content")) @@ -38,7 +38,7 @@ internal class CollapseTest { ) } - composeTestRule.onNodeWithTag("title").assertIsDisplayed() + composeTestRule.onNodeWithTag("title", useUnmergedTree = true).assertIsDisplayed() composeTestRule.onNodeWithTag("content").assertDoesNotExist() composeTestRule.onNodeWithTag("collapse").performSemanticsAction(SemanticsActions.Expand) diff --git a/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse.png b/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse.png index 1275a8224..59fac7d9f 100644 --- a/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse.png +++ b/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:999bb53a906c806a48e50e8735d370a9561ee305b65c6caeb6f9903e6c778860 -size 19468 +oid sha256:b28a9a7006eb6f3f2747ec4706292b9f8cb32c2860e031bb3063c896af1e9818 +size 19724 diff --git a/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse_big.png b/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse_big.png index ea602411f..30b653f1f 100644 --- a/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse_big.png +++ b/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse_big.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02651701bd3f5238d9b8636d9d9f72fa53506e83478ce223db475ffa9ff47e8c -size 28675 +oid sha256:5176d2250d559789ef14002d4f944eb8150738f2de2473e4d55e3066dc2f4c78 +size 30419 diff --git a/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse_dark.png b/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse_dark.png index 740f51220..2670bd6b2 100644 --- a/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse_dark.png +++ b/ui/src/test/snapshots/images/kiwi.orbit.compose.ui_ScreenshotTest_collapse_dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a3d58152887383040d5e214ef363d61d3f05802286805de9f23b3166c0c1b320 -size 20160 +oid sha256:4301268d1125989096fb8445ea21286c55538b9d422751a3ce963c4c57589ad1 +size 20276