@expo/ui 55.0.4 → 55.0.6

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 (97) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/AlertDialogView.kt +56 -28
  4. package/android/src/main/java/expo/modules/ui/BasicAlertDialogView.kt +9 -1
  5. package/android/src/main/java/expo/modules/ui/CarouselView.kt +93 -67
  6. package/android/src/main/java/expo/modules/ui/DividerView.kt +21 -2
  7. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +25 -17
  8. package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +6 -0
  9. package/android/src/main/java/expo/modules/ui/PullToRefreshBoxView.kt +20 -3
  10. package/android/src/main/java/expo/modules/ui/SlotView.kt +8 -0
  11. package/android/src/main/java/expo/modules/ui/SurfaceView.kt +88 -11
  12. package/android/src/main/java/expo/modules/ui/TextInputView.kt +15 -3
  13. package/android/src/main/java/expo/modules/ui/TextView.kt +145 -12
  14. package/build/jetpack-compose/AlertDialog/index.d.ts +72 -36
  15. package/build/jetpack-compose/AlertDialog/index.d.ts.map +1 -1
  16. package/build/jetpack-compose/BasicAlertDialog/index.d.ts +7 -2
  17. package/build/jetpack-compose/BasicAlertDialog/index.d.ts.map +1 -1
  18. package/build/jetpack-compose/Card/index.d.ts.map +1 -1
  19. package/build/jetpack-compose/Carousel/index.d.ts +86 -23
  20. package/build/jetpack-compose/Carousel/index.d.ts.map +1 -1
  21. package/build/jetpack-compose/Divider/index.d.ts +20 -5
  22. package/build/jetpack-compose/Divider/index.d.ts.map +1 -1
  23. package/build/jetpack-compose/Progress/index.d.ts +6 -7
  24. package/build/jetpack-compose/Progress/index.d.ts.map +1 -1
  25. package/build/jetpack-compose/PullToRefreshBox/index.d.ts +34 -9
  26. package/build/jetpack-compose/PullToRefreshBox/index.d.ts.map +1 -1
  27. package/build/jetpack-compose/Surface/index.d.ts +52 -2
  28. package/build/jetpack-compose/Surface/index.d.ts.map +1 -1
  29. package/build/jetpack-compose/Text/index.d.ts +77 -89
  30. package/build/jetpack-compose/Text/index.d.ts.map +1 -1
  31. package/build/jetpack-compose/TextInput/index.d.ts +18 -3
  32. package/build/jetpack-compose/TextInput/index.d.ts.map +1 -1
  33. package/build/jetpack-compose/index.d.ts +2 -2
  34. package/build/jetpack-compose/index.d.ts.map +1 -1
  35. package/build/jetpack-compose/modifiers/index.d.ts +5 -0
  36. package/build/jetpack-compose/modifiers/index.d.ts.map +1 -1
  37. package/build/swift-ui/modifiers/index.d.ts +1 -1
  38. package/build/types.d.ts +26 -0
  39. package/build/types.d.ts.map +1 -1
  40. package/expo-module.config.json +1 -1
  41. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{55.0.4/expo.modules.ui-55.0.4-sources.jar → 55.0.6/expo.modules.ui-55.0.6-sources.jar} +0 -0
  42. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6-sources.jar.md5 +1 -0
  43. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6-sources.jar.sha1 +1 -0
  44. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6-sources.jar.sha256 +1 -0
  45. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6-sources.jar.sha512 +1 -0
  46. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.aar +0 -0
  47. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.aar.md5 +1 -0
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.aar.sha1 +1 -0
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.aar.sha256 +1 -0
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.aar.sha512 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{55.0.4/expo.modules.ui-55.0.4.module → 55.0.6/expo.modules.ui-55.0.6.module} +22 -22
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.module.md5 +1 -0
  53. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.module.sha1 +1 -0
  54. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.module.sha256 +1 -0
  55. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.module.sha512 +1 -0
  56. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{55.0.4/expo.modules.ui-55.0.4.pom → 55.0.6/expo.modules.ui-55.0.6.pom} +1 -1
  57. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.pom.md5 +1 -0
  58. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.pom.sha1 +1 -0
  59. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.pom.sha256 +1 -0
  60. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.6/expo.modules.ui-55.0.6.pom.sha512 +1 -0
  61. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
  62. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
  63. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
  64. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
  65. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
  66. package/package.json +2 -2
  67. package/src/jetpack-compose/AlertDialog/index.tsx +94 -41
  68. package/src/jetpack-compose/BasicAlertDialog/index.tsx +9 -2
  69. package/src/jetpack-compose/Card/index.tsx +4 -2
  70. package/src/jetpack-compose/Carousel/index.tsx +118 -30
  71. package/src/jetpack-compose/Divider/index.tsx +34 -14
  72. package/src/jetpack-compose/Progress/index.tsx +11 -9
  73. package/src/jetpack-compose/PullToRefreshBox/index.tsx +35 -18
  74. package/src/jetpack-compose/Surface/index.tsx +75 -4
  75. package/src/jetpack-compose/Text/index.tsx +171 -101
  76. package/src/jetpack-compose/TextInput/index.tsx +38 -8
  77. package/src/jetpack-compose/index.ts +2 -2
  78. package/src/jetpack-compose/modifiers/index.ts +10 -0
  79. package/src/swift-ui/modifiers/index.ts +1 -1
  80. package/src/types.ts +27 -0
  81. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4-sources.jar.md5 +0 -1
  82. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4-sources.jar.sha1 +0 -1
  83. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4-sources.jar.sha256 +0 -1
  84. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4-sources.jar.sha512 +0 -1
  85. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.aar +0 -0
  86. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.aar.md5 +0 -1
  87. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.aar.sha1 +0 -1
  88. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.aar.sha256 +0 -1
  89. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.aar.sha512 +0 -1
  90. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.module.md5 +0 -1
  91. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.module.sha1 +0 -1
  92. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.module.sha256 +0 -1
  93. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.module.sha512 +0 -1
  94. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.pom.md5 +0 -1
  95. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.pom.sha1 +0 -1
  96. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.pom.sha256 +0 -1
  97. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.4/expo.modules.ui-55.0.4.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,24 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 55.0.6 — 2026-03-27
14
+
15
+ ### 🛠 Breaking changes
16
+
17
+ - [android] Refactored `PullToRefreshBox` indicator props: replaced `loadingIndicatorModifiers` with nested `indicator` prop containing `color`, `containerColor`, and `modifiers`. Added `contentAlignment` prop. ([#44079](https://github.com/expo/expo/pull/44079) by [@nishan](https://github.com/intergalacticspacehighway))
18
+ - [android] Split `Divider` into `HorizontalDivider` and `VerticalDivider` matching native Compose components. Added `thickness` and `color` props. ([#44035](https://github.com/expo/expo/pull/44035) by [@nishan](https://github.com/intergalacticspacehighway))
19
+ - [android] Match `AlertDialog` API to native Compose: replaced string props (`title`, `text`, `confirmButtonText`, `dismissButtonText`) with slot sub-components (`AlertDialog.Title`, `AlertDialog.Text`, `AlertDialog.ConfirmButton`, `AlertDialog.DismissButton`, `AlertDialog.Icon`). Removed `visible` prop (use conditional rendering), `onConfirmPressed`/`onDismissPressed` (renamed to `onDismissRequest`), and `confirmButtonColors`/`dismissButtonColors` (replaced with dialog-level `colors`). ([#43997](https://github.com/expo/expo/pull/43997) by [@nishan](https://github.com/intergalacticspacehighway))
20
+
21
+ ### 🎉 New features
22
+
23
+ - [android] add `imePadding` modifier ([#43652](https://github.com/expo/expo/pull/43652) by [@Ubax](https://github.com/Ubax))
24
+
25
+ ## 55.0.5 — 2026-03-19
26
+
27
+ ### 🛠 Breaking changes
28
+
29
+ - [android] Split `Carousel` into `HorizontalCenteredHeroCarousel`, `HorizontalMultiBrowseCarousel`, and `HorizontalUncontainedCarousel` matching native Compose components. Added `HorizontalCenteredHeroCarousel`. ([#44034](https://github.com/expo/expo/pull/44034) by [@nishan](https://github.com/intergalacticspacehighway))
30
+
13
31
  ## 55.0.4 — 2026-03-18
14
32
 
15
33
  ### 🎉 New features
@@ -37,8 +55,10 @@
37
55
 
38
56
  ### 🎉 New features
39
57
 
58
+ - [android] Added `shape`, `border`, `selected`, `checked`, `onClick`, and `onCheckedChange` props to `Surface`, supporting clickable, selectable, and toggleable variants. ([#44079](https://github.com/expo/expo/pull/44079) by [@nishan](https://github.com/intergalacticspacehighway))
59
+ - [android] Added nested text support for Compose `Text` with style inheritance, custom fonts via `expo-font`, `background`, `shadow`, and `lineBreak` properties. ([#44094](https://github.com/expo/expo/pull/44094) by [@nishan](https://github.com/intergalacticspacehighway))
40
60
  - [android] Added `outlined` variant to `TextInput` component. ([#43719](https://github.com/expo/expo/pull/43719) by [@benjaminkomen](https://github.com/benjaminkomen))
41
- - Added `@expo/ui/datetimepicker` — a cross-platform `DateTimePicker` drop-in replacement for `@react-native-community/datetimepicker`. ([#44014](https://github.com/expo/expo/pull/44014) by [@vonovak](https://github.com/vonovak))
61
+ - Added `@expo/ui/datetimepicker` — a cross-platform `DateTimePicker` drop-in replacement for `@react-native-community/datetimepicker`. ([#44014](https://github.com/expo/expo/pull/44014) by [@vonovak](https://github.com/vonovak))
42
62
  - [iOS] Added `locale` and `timeZone` support to `modifiers`. ([#44013](https://github.com/expo/expo/pull/44013) by [@vonovak](https://github.com/vonovak))
43
63
  - [android] Added `ref.hide()` for animated dismiss and more configurable props (`containerColor`, `contentColor`, `scrimColor`, `showDragHandle`, `sheetGesturesEnabled`, `properties`, `DragHandle` slot) to `BottomSheet`. ([#43972](https://github.com/expo/expo/pull/43972) by [@nishan](https://github.com/intergalacticspacehighway))
44
64
  - [iOS] Added `date`, `dateStyle`, `timerInterval`, `countsDown`, and `pauseTime` props to `Text` component for displaying auto-updating dates, timers, and countdowns using SwiftUI's `Text.DateStyle`. ([#43552](https://github.com/expo/expo/pull/43552) by [@LouisRaverdy](https://github.com/LouisRaverdy))
@@ -238,6 +258,7 @@ _This version does not introduce any user-facing changes._
238
258
 
239
259
  ### 🎉 New features
240
260
 
261
+ - [Android] Add `label`, and `placeholder` props to TextField component. ([#40452](https://github.com/expo/expo/pull/40452) by [@akshayjadhav4](https://github.com/akshayjadhav4))
241
262
  - [iOS] Add `refreshable` modifier. ([#40201](https://github.com/expo/expo/pull/40201) by [@christianwooldridge](https://github.com/christianwooldridge))
242
263
  - [iOS] Add RTL support in swiftui. ([#40335](https://github.com/expo/expo/pull/40335) by [@kfirfitousi](https://github.com/kfirfitousi))
243
264
  - [Android] Add Carousel component. ([#40325](https://github.com/expo/expo/pull/40325) by [@aleqsio](https://github.com/aleqsio))
@@ -12,13 +12,13 @@ apply plugin: 'expo-module-gradle-plugin'
12
12
  apply plugin: 'org.jetbrains.kotlin.plugin.compose'
13
13
 
14
14
  group = 'expo.modules.ui'
15
- version = '55.0.4'
15
+ version = '55.0.6'
16
16
 
17
17
  android {
18
18
  namespace "expo.modules.ui"
19
19
  defaultConfig {
20
20
  versionCode 1
21
- versionName "55.0.4"
21
+ versionName "55.0.6"
22
22
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
23
23
  }
24
24
  buildFeatures {
@@ -1,52 +1,80 @@
1
1
  package expo.modules.ui
2
2
 
3
+ import android.graphics.Color
3
4
  import androidx.compose.material3.AlertDialog
4
- import androidx.compose.material3.Text
5
- import androidx.compose.material3.TextButton
5
+ import androidx.compose.material3.AlertDialogDefaults
6
6
  import androidx.compose.runtime.Composable
7
+ import androidx.compose.ui.unit.dp
8
+ import androidx.compose.ui.window.DialogProperties
9
+ import expo.modules.kotlin.records.Field
7
10
  import expo.modules.kotlin.records.Record
8
11
  import expo.modules.kotlin.views.ComposeProps
9
12
  import expo.modules.kotlin.views.FunctionalComposableScope
10
- import java.io.Serializable
11
13
 
12
- open class AlertDialogButtonPressedEvent() : Record, Serializable
14
+ data class AlertDialogColors(
15
+ @Field val containerColor: Color? = null,
16
+ @Field val iconContentColor: Color? = null,
17
+ @Field val titleContentColor: Color? = null,
18
+ @Field val textContentColor: Color? = null
19
+ ) : Record
20
+
21
+ data class ExpoDialogProperties(
22
+ @Field val dismissOnBackPress: Boolean = true,
23
+ @Field val dismissOnClickOutside: Boolean = true,
24
+ @Field val usePlatformDefaultWidth: Boolean = true,
25
+ @Field val decorFitsSystemWindows: Boolean = true
26
+ ) : Record
13
27
 
14
28
  data class AlertDialogProps(
15
- val title: String? = null,
16
- val text: String? = null,
17
- val confirmButtonText: String? = null,
18
- val dismissButtonText: String? = null,
19
- val visible: Boolean = false,
29
+ val colors: AlertDialogColors = AlertDialogColors(),
30
+ val tonalElevation: Double? = null,
31
+ val properties: ExpoDialogProperties = ExpoDialogProperties(),
20
32
  val modifiers: ModifierList = emptyList()
21
33
  ) : ComposeProps
22
34
 
23
35
  @Composable
24
36
  fun FunctionalComposableScope.AlertDialogContent(
25
37
  props: AlertDialogProps,
26
- onDismissPressed: (AlertDialogButtonPressedEvent) -> Unit,
27
- onConfirmPressed: (AlertDialogButtonPressedEvent) -> Unit
38
+ onDismissRequest: () -> Unit
28
39
  ) {
29
- if (!props.visible) {
30
- return
31
- }
40
+ val titleSlotView = findChildSlotView(view, "title")
41
+ val textSlotView = findChildSlotView(view, "text")
42
+ val confirmButtonSlotView = findChildSlotView(view, "confirmButton")
43
+ val dismissButtonSlotView = findChildSlotView(view, "dismissButton")
44
+ val iconSlotView = findChildSlotView(view, "icon")
32
45
 
33
46
  AlertDialog(
47
+ onDismissRequest = { onDismissRequest() },
34
48
  confirmButton = {
35
- props.confirmButtonText?.let {
36
- TextButton(onClick = { onConfirmPressed(AlertDialogButtonPressedEvent()) }) {
37
- Text(it)
38
- }
39
- }
49
+ confirmButtonSlotView?.renderSlot()
50
+ },
51
+ modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
52
+ dismissButton = dismissButtonSlotView?.let {
53
+ { it.renderSlot() }
54
+ },
55
+ title = titleSlotView?.let {
56
+ { it.renderSlot() }
57
+ },
58
+ text = textSlotView?.let {
59
+ { it.renderSlot() }
40
60
  },
41
- dismissButton = {
42
- props.dismissButtonText?.let {
43
- TextButton(onClick = { onDismissPressed(AlertDialogButtonPressedEvent()) }) {
44
- Text(it)
45
- }
46
- }
61
+ icon = iconSlotView?.let {
62
+ { it.renderSlot() }
47
63
  },
48
- onDismissRequest = { onDismissPressed(AlertDialogButtonPressedEvent()) },
49
- title = { props.title?.let { Text(it) } },
50
- text = { props.text?.let { Text(it) } }
64
+ containerColor = props.colors.containerColor.composeOrNull
65
+ ?: AlertDialogDefaults.containerColor,
66
+ iconContentColor = props.colors.iconContentColor.composeOrNull
67
+ ?: AlertDialogDefaults.iconContentColor,
68
+ titleContentColor = props.colors.titleContentColor.composeOrNull
69
+ ?: AlertDialogDefaults.titleContentColor,
70
+ textContentColor = props.colors.textContentColor.composeOrNull
71
+ ?: AlertDialogDefaults.textContentColor,
72
+ tonalElevation = props.tonalElevation?.dp ?: AlertDialogDefaults.TonalElevation,
73
+ properties = DialogProperties(
74
+ dismissOnBackPress = props.properties.dismissOnBackPress,
75
+ dismissOnClickOutside = props.properties.dismissOnClickOutside,
76
+ usePlatformDefaultWidth = props.properties.usePlatformDefaultWidth,
77
+ decorFitsSystemWindows = props.properties.decorFitsSystemWindows
78
+ )
51
79
  )
52
80
  }
@@ -3,11 +3,13 @@ package expo.modules.ui
3
3
  import androidx.compose.material3.BasicAlertDialog
4
4
  import androidx.compose.material3.ExperimentalMaterial3Api
5
5
  import androidx.compose.runtime.Composable
6
+ import androidx.compose.ui.window.DialogProperties
6
7
  import expo.modules.kotlin.views.ComposableScope
7
8
  import expo.modules.kotlin.views.ComposeProps
8
9
  import expo.modules.kotlin.views.FunctionalComposableScope
9
10
 
10
11
  data class BasicAlertDialogProps(
12
+ val properties: ExpoDialogProperties = ExpoDialogProperties(),
11
13
  val modifiers: ModifierList = emptyList()
12
14
  ) : ComposeProps
13
15
 
@@ -19,7 +21,13 @@ fun FunctionalComposableScope.BasicAlertDialogContent(
19
21
  ) {
20
22
  BasicAlertDialog(
21
23
  onDismissRequest = { onDismissRequest() },
22
- modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
24
+ modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
25
+ properties = DialogProperties(
26
+ dismissOnBackPress = props.properties.dismissOnBackPress,
27
+ dismissOnClickOutside = props.properties.dismissOnClickOutside,
28
+ usePlatformDefaultWidth = props.properties.usePlatformDefaultWidth,
29
+ decorFitsSystemWindows = props.properties.decorFitsSystemWindows
30
+ )
23
31
  ) {
24
32
  Children(ComposableScope())
25
33
  }
@@ -4,10 +4,12 @@ import androidx.compose.foundation.gestures.TargetedFlingBehavior
4
4
  import androidx.compose.foundation.layout.PaddingValues
5
5
  import androidx.compose.material3.ExperimentalMaterial3Api
6
6
  import androidx.compose.material3.carousel.CarouselDefaults
7
+ import androidx.compose.material3.carousel.HorizontalCenteredHeroCarousel
7
8
  import androidx.compose.material3.carousel.HorizontalMultiBrowseCarousel
8
9
  import androidx.compose.material3.carousel.HorizontalUncontainedCarousel
9
10
  import androidx.compose.material3.carousel.rememberCarouselState
10
11
  import androidx.compose.runtime.Composable
12
+ import androidx.compose.ui.unit.Dp
11
13
  import androidx.compose.ui.unit.dp
12
14
  import androidx.core.view.size
13
15
  import expo.modules.kotlin.records.Field
@@ -18,28 +20,16 @@ import expo.modules.kotlin.views.ComposableScope
18
20
  import expo.modules.kotlin.views.ComposeProps
19
21
  import expo.modules.kotlin.views.FunctionalComposableScope
20
22
 
21
- enum class CarouselVariant(val value: String) : Enumerable {
22
- MULTI_BROWSE("multiBrowse"),
23
- UNCONSTRAINED("unconstrained")
24
- }
25
-
26
23
  enum class FlingBehaviorType(val value: String) : Enumerable {
27
24
  SINGLE_ADVANCE("singleAdvance"),
28
25
  NO_SNAP("noSnap")
29
26
  }
30
27
 
31
28
  class PaddingValuesRecord : Record {
32
- @Field
33
- val start: Float? = null
34
-
35
- @Field
36
- val top: Float? = null
37
-
38
- @Field
39
- val end: Float? = null
40
-
41
- @Field
42
- val bottom: Float? = null
29
+ @Field val start: Float? = null
30
+ @Field val top: Float? = null
31
+ @Field val end: Float? = null
32
+ @Field val bottom: Float? = null
43
33
 
44
34
  fun toPaddingValues(): PaddingValues {
45
35
  return PaddingValues(
@@ -63,77 +53,113 @@ fun paddingValuesFromEither(either: Either<Float, PaddingValuesRecord>?): Paddin
63
53
  }
64
54
  }
65
55
 
66
- data class CarouselProps(
67
- val variant: CarouselVariant? = null,
56
+ data class HorizontalCenteredHeroCarouselProps(
57
+ val maxItemWidth: Float? = null,
68
58
  val itemSpacing: Float? = null,
69
59
  val contentPadding: Either<Float, PaddingValuesRecord>? = null,
70
60
  val minSmallItemWidth: Float? = null,
71
61
  val maxSmallItemWidth: Float? = null,
72
62
  val flingBehavior: FlingBehaviorType? = null,
73
- val preferredItemWidth: Float? = null,
74
- val itemWidth: Float? = null,
63
+ val userScrollEnabled: Boolean? = null,
75
64
  val modifiers: ModifierList = emptyList()
76
65
  ) : ComposeProps
77
66
 
78
- const val DEFAULT_MIN_SMALL_ITEM_WIDTH = 40f
79
- const val DEFAULT_MAX_SMALL_ITEM_WIDTH = 56f
80
- const val DEFAULT_PREFERRED_ITEM_WIDTH = 200f
81
- const val DEFAULT_ITEM_WIDTH = 200f
82
-
83
67
  @OptIn(ExperimentalMaterial3Api::class)
84
68
  @Composable
85
- fun FunctionalComposableScope.CarouselContent(props: CarouselProps) {
86
- val variant = props.variant ?: CarouselVariant.MULTI_BROWSE
87
- val modifiers = props.modifiers ?: emptyList()
88
- val itemSpacing = (props.itemSpacing ?: 0f).dp
89
- val minSmallItemWidth = (props.minSmallItemWidth ?: DEFAULT_MIN_SMALL_ITEM_WIDTH).dp
90
-
91
- // we need to constrain maxSmallItemWidth to be at least minSmallItemWidth or the app will crash
92
- val maxSmallItemWidth = minSmallItemWidth.coerceAtLeast((props.maxSmallItemWidth ?: DEFAULT_MAX_SMALL_ITEM_WIDTH).dp)
93
- val preferredItemWidth = (props.preferredItemWidth ?: DEFAULT_PREFERRED_ITEM_WIDTH).dp
94
- val itemWidth = (props.itemWidth ?: DEFAULT_ITEM_WIDTH).dp
95
- val flingBehaviorType = props.flingBehavior ?: FlingBehaviorType.SINGLE_ADVANCE
69
+ fun FunctionalComposableScope.HorizontalCenteredHeroCarouselContent(props: HorizontalCenteredHeroCarouselProps) {
96
70
  val contentPadding = paddingValuesFromEither(props.contentPadding)
97
-
98
71
  val carouselState = rememberCarouselState(0) { view.size }
72
+ val flingBehavior: TargetedFlingBehavior = when (props.flingBehavior ?: FlingBehaviorType.SINGLE_ADVANCE) {
73
+ FlingBehaviorType.SINGLE_ADVANCE -> CarouselDefaults.singleAdvanceFlingBehavior(state = carouselState)
74
+ FlingBehaviorType.NO_SNAP -> CarouselDefaults.noSnapFlingBehavior()
75
+ }
76
+
77
+ val minSmallItemWidth = props.minSmallItemWidth?.dp ?: CarouselDefaults.MinSmallItemSize
78
+ val maxSmallItemWidth = (props.maxSmallItemWidth?.dp ?: CarouselDefaults.MaxSmallItemSize).coerceAtLeast(minSmallItemWidth)
79
+
80
+ HorizontalCenteredHeroCarousel(
81
+ state = carouselState,
82
+ modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
83
+ maxItemWidth = props.maxItemWidth?.dp ?: Dp.Unspecified,
84
+ itemSpacing = (props.itemSpacing ?: 0f).dp,
85
+ flingBehavior = flingBehavior,
86
+ userScrollEnabled = props.userScrollEnabled ?: true,
87
+ minSmallItemWidth = minSmallItemWidth,
88
+ maxSmallItemWidth = maxSmallItemWidth,
89
+ contentPadding = contentPadding
90
+ ) { itemIndex ->
91
+ Child(ComposableScope(), itemIndex)
92
+ }
93
+ }
94
+
95
+ data class HorizontalMultiBrowseCarouselProps(
96
+ val preferredItemWidth: Float = 200f,
97
+ val itemSpacing: Float? = null,
98
+ val contentPadding: Either<Float, PaddingValuesRecord>? = null,
99
+ val minSmallItemWidth: Float? = null,
100
+ val maxSmallItemWidth: Float? = null,
101
+ val flingBehavior: FlingBehaviorType? = null,
102
+ val userScrollEnabled: Boolean? = null,
103
+ val modifiers: ModifierList = emptyList()
104
+ ) : ComposeProps
99
105
 
100
- val flingBehavior: TargetedFlingBehavior = when (flingBehaviorType) {
106
+ @OptIn(ExperimentalMaterial3Api::class)
107
+ @Composable
108
+ fun FunctionalComposableScope.HorizontalMultiBrowseCarouselContent(props: HorizontalMultiBrowseCarouselProps) {
109
+ val contentPadding = paddingValuesFromEither(props.contentPadding)
110
+ val carouselState = rememberCarouselState(0) { view.size }
111
+ val flingBehavior: TargetedFlingBehavior = when (props.flingBehavior ?: FlingBehaviorType.SINGLE_ADVANCE) {
101
112
  FlingBehaviorType.SINGLE_ADVANCE -> CarouselDefaults.singleAdvanceFlingBehavior(state = carouselState)
102
113
  FlingBehaviorType.NO_SNAP -> CarouselDefaults.noSnapFlingBehavior()
103
114
  }
104
115
 
105
- @Composable
106
- fun MultiBrowseCarouselComposable() {
107
- HorizontalMultiBrowseCarousel(
108
- state = carouselState,
109
- preferredItemWidth = preferredItemWidth,
110
- modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
111
- itemSpacing = itemSpacing,
112
- flingBehavior = flingBehavior,
113
- minSmallItemWidth = minSmallItemWidth,
114
- maxSmallItemWidth = maxSmallItemWidth,
115
- contentPadding = contentPadding
116
- ) { itemIndex ->
117
- Child(ComposableScope(), itemIndex)
118
- }
116
+ val minSmallItemWidth = props.minSmallItemWidth?.dp ?: CarouselDefaults.MinSmallItemSize
117
+ val maxSmallItemWidth = (props.maxSmallItemWidth?.dp ?: CarouselDefaults.MaxSmallItemSize).coerceAtLeast(minSmallItemWidth)
118
+
119
+ HorizontalMultiBrowseCarousel(
120
+ state = carouselState,
121
+ preferredItemWidth = props.preferredItemWidth.dp,
122
+ modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
123
+ itemSpacing = (props.itemSpacing ?: 0f).dp,
124
+ flingBehavior = flingBehavior,
125
+ userScrollEnabled = props.userScrollEnabled ?: true,
126
+ minSmallItemWidth = minSmallItemWidth,
127
+ maxSmallItemWidth = maxSmallItemWidth,
128
+ contentPadding = contentPadding
129
+ ) { itemIndex ->
130
+ Child(ComposableScope(), itemIndex)
119
131
  }
132
+ }
120
133
 
121
- @Composable
122
- fun UnconstrainedCarouselComposable() {
123
- HorizontalUncontainedCarousel(
124
- state = carouselState,
125
- itemWidth = itemWidth,
126
- modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
127
- itemSpacing = itemSpacing,
128
- flingBehavior = flingBehavior,
129
- contentPadding = contentPadding
130
- ) { itemIndex ->
131
- Child(ComposableScope(), itemIndex)
132
- }
134
+ data class HorizontalUncontainedCarouselProps(
135
+ val itemWidth: Float = 200f,
136
+ val itemSpacing: Float? = null,
137
+ val contentPadding: Either<Float, PaddingValuesRecord>? = null,
138
+ val flingBehavior: FlingBehaviorType? = null,
139
+ val userScrollEnabled: Boolean? = null,
140
+ val modifiers: ModifierList = emptyList()
141
+ ) : ComposeProps
142
+
143
+ @OptIn(ExperimentalMaterial3Api::class)
144
+ @Composable
145
+ fun FunctionalComposableScope.HorizontalUncontainedCarouselContent(props: HorizontalUncontainedCarouselProps) {
146
+ val contentPadding = paddingValuesFromEither(props.contentPadding)
147
+ val carouselState = rememberCarouselState(0) { view.size }
148
+ // Uncontained defaults to noSnap, unlike the other two which default to singleAdvance
149
+ val flingBehavior: TargetedFlingBehavior = when (props.flingBehavior ?: FlingBehaviorType.NO_SNAP) {
150
+ FlingBehaviorType.SINGLE_ADVANCE -> CarouselDefaults.singleAdvanceFlingBehavior(state = carouselState)
151
+ FlingBehaviorType.NO_SNAP -> CarouselDefaults.noSnapFlingBehavior()
133
152
  }
134
153
 
135
- when (variant) {
136
- CarouselVariant.MULTI_BROWSE -> MultiBrowseCarouselComposable()
137
- CarouselVariant.UNCONSTRAINED -> UnconstrainedCarouselComposable()
154
+ HorizontalUncontainedCarousel(
155
+ state = carouselState,
156
+ itemWidth = props.itemWidth.dp,
157
+ modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
158
+ itemSpacing = (props.itemSpacing ?: 0f).dp,
159
+ flingBehavior = flingBehavior,
160
+ userScrollEnabled = props.userScrollEnabled ?: true,
161
+ contentPadding = contentPadding
162
+ ) { itemIndex ->
163
+ Child(ComposableScope(), itemIndex)
138
164
  }
139
165
  }
@@ -1,15 +1,34 @@
1
1
  package expo.modules.ui
2
2
 
3
+ import android.graphics.Color
4
+ import androidx.compose.material3.DividerDefaults
3
5
  import androidx.compose.material3.HorizontalDivider
6
+ import androidx.compose.material3.VerticalDivider
4
7
  import androidx.compose.runtime.Composable
8
+ import androidx.compose.ui.unit.dp
5
9
  import expo.modules.kotlin.views.ComposeProps
6
10
  import expo.modules.kotlin.views.FunctionalComposableScope
7
11
 
8
12
  data class DividerProps(
13
+ val thickness: Float? = null,
14
+ val color: Color? = null,
9
15
  val modifiers: ModifierList = emptyList()
10
16
  ) : ComposeProps
11
17
 
12
18
  @Composable
13
- fun FunctionalComposableScope.DividerContent(props: DividerProps) {
14
- HorizontalDivider(modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher))
19
+ fun FunctionalComposableScope.HorizontalDividerContent(props: DividerProps) {
20
+ HorizontalDivider(
21
+ modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
22
+ thickness = props.thickness?.dp ?: DividerDefaults.Thickness,
23
+ color = props.color.composeOrNull ?: DividerDefaults.color
24
+ )
25
+ }
26
+
27
+ @Composable
28
+ fun FunctionalComposableScope.VerticalDividerContent(props: DividerProps) {
29
+ VerticalDivider(
30
+ modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher),
31
+ thickness = props.thickness?.dp ?: DividerDefaults.Thickness,
32
+ color = props.color.composeOrNull ?: DividerDefaults.color
33
+ )
15
34
  }
@@ -210,8 +210,12 @@ class ExpoUIModule : Module() {
210
210
  ShapeContent(props)
211
211
  }
212
212
 
213
- ExpoUIView("DividerView") { props: DividerProps ->
214
- DividerContent(props)
213
+ ExpoUIView("HorizontalDividerView") { props: DividerProps ->
214
+ HorizontalDividerContent(props)
215
+ }
216
+
217
+ ExpoUIView("VerticalDividerView") { props: DividerProps ->
218
+ VerticalDividerContent(props)
215
219
  }
216
220
 
217
221
  ExpoUIView("DateTimePickerView", events = {
@@ -312,23 +316,23 @@ class ExpoUIModule : Module() {
312
316
  PullToRefreshBoxContent(props) { onRefresh(Unit) }
313
317
  }
314
318
 
315
- ExpoUIView("CarouselView") { props: CarouselProps ->
316
- CarouselContent(props)
319
+ ExpoUIView("HorizontalCenteredHeroCarouselView") { props: HorizontalCenteredHeroCarouselProps ->
320
+ HorizontalCenteredHeroCarouselContent(props)
321
+ }
322
+
323
+ ExpoUIView("HorizontalMultiBrowseCarouselView") { props: HorizontalMultiBrowseCarouselProps ->
324
+ HorizontalMultiBrowseCarouselContent(props)
325
+ }
326
+
327
+ ExpoUIView("HorizontalUncontainedCarouselView") { props: HorizontalUncontainedCarouselProps ->
328
+ HorizontalUncontainedCarouselContent(props)
317
329
  }
318
330
 
319
331
  ExpoUIView("AlertDialogView", events = {
320
- Events(
321
- "onDismissPressed",
322
- "onConfirmPressed"
323
- )
332
+ Events("onDismissRequest")
324
333
  }) { props: AlertDialogProps ->
325
- val onDismissPressed by remember { EventDispatcher<AlertDialogButtonPressedEvent>() }
326
- val onConfirmPressed by remember { EventDispatcher<AlertDialogButtonPressedEvent>() }
327
- AlertDialogContent(
328
- props,
329
- { onDismissPressed(it) },
330
- { onConfirmPressed(it) }
331
- )
334
+ val onDismissRequest by remember { EventDispatcher<Unit>() }
335
+ AlertDialogContent(props) { onDismissRequest(Unit) }
332
336
  }
333
337
 
334
338
  ExpoUIView("AssistChipView", events = {
@@ -414,8 +418,12 @@ class ExpoUIModule : Module() {
414
418
  BasicAlertDialogContent(props) { onDismissRequest(Unit) }
415
419
  }
416
420
 
417
- ExpoUIView("SurfaceView") { props: SurfaceProps ->
418
- SurfaceContent(props)
421
+ ExpoUIView("SurfaceView", events = {
422
+ Events("onSurfaceClick", "onCheckedChange")
423
+ }) { props: SurfaceProps ->
424
+ val onSurfaceClick by remember { EventDispatcher<Unit>() }
425
+ val onCheckedChange by remember { EventDispatcher<GenericEventPayload1<Boolean>>() }
426
+ SurfaceContent(props, onClick = { onSurfaceClick(Unit) }, onCheckedChange = { onCheckedChange(GenericEventPayload1(it)) })
419
427
  }
420
428
 
421
429
  ExpoUIView("AnimatedVisibilityView") { props: AnimatedVisibilityProps ->
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.fillMaxHeight
14
14
  import androidx.compose.foundation.layout.fillMaxSize
15
15
  import androidx.compose.foundation.layout.fillMaxWidth
16
16
  import androidx.compose.foundation.layout.height
17
+ import androidx.compose.foundation.layout.imePadding
17
18
  import androidx.compose.foundation.layout.offset
18
19
  import androidx.compose.foundation.layout.padding
19
20
  import androidx.compose.foundation.layout.size
@@ -365,6 +366,11 @@ object ModifierRegistry {
365
366
  } ?: Modifier.wrapContentHeight()
366
367
  }
367
368
 
369
+ // Inset modifiers
370
+ register("imePadding") { _, _, _, _ ->
371
+ Modifier.imePadding()
372
+ }
373
+
368
374
  // Position modifiers
369
375
  register("offset") { map, _, _, _ ->
370
376
  val params = recordFromMap<OffsetParams>(map)
@@ -2,19 +2,33 @@
2
2
 
3
3
  package expo.modules.ui
4
4
 
5
+ import android.graphics.Color
5
6
  import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
7
+ import androidx.compose.material3.MaterialTheme
6
8
  import androidx.compose.material3.pulltorefresh.PullToRefreshBox
7
9
  import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
8
10
  import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
9
11
  import androidx.compose.runtime.Composable
12
+ import androidx.compose.ui.Alignment
13
+ import androidx.compose.ui.Modifier
10
14
  import expo.modules.kotlin.views.ComposableScope
11
15
  import expo.modules.kotlin.views.ComposeProps
12
16
  import expo.modules.kotlin.views.FunctionalComposableScope
17
+ import expo.modules.kotlin.records.Field
18
+ import expo.modules.kotlin.records.Record
19
+ import expo.modules.ui.convertibles.ContentAlignment
20
+
21
+ data class PullToRefreshIndicatorProps(
22
+ @Field val color: Color? = null,
23
+ @Field val containerColor: Color? = null,
24
+ @Field val modifiers: ModifierList = emptyList()
25
+ ) : Record
13
26
 
14
27
  data class PullToRefreshBoxProps(
15
28
  val isRefreshing: Boolean = false,
16
- val modifiers: ModifierList = emptyList(),
17
- val loadingIndicatorModifiers: ModifierList = emptyList()
29
+ val contentAlignment: ContentAlignment? = null,
30
+ val indicator: PullToRefreshIndicatorProps = PullToRefreshIndicatorProps(),
31
+ val modifiers: ModifierList = emptyList()
18
32
  ) : ComposeProps
19
33
 
20
34
  @Composable
@@ -26,11 +40,14 @@ fun FunctionalComposableScope.PullToRefreshBoxContent(props: PullToRefreshBoxPro
26
40
  isRefreshing = isRefreshing,
27
41
  onRefresh = { onRefresh() },
28
42
  state = pullToRefreshState,
43
+ contentAlignment = props.contentAlignment?.toComposeAlignment() ?: Alignment.TopStart,
29
44
  indicator = {
30
45
  PullToRefreshDefaults.LoadingIndicator(
31
46
  isRefreshing = isRefreshing,
32
47
  state = pullToRefreshState,
33
- modifier = ModifierRegistry.applyModifiers(props.loadingIndicatorModifiers, appContext, composableScope, globalEventDispatcher)
48
+ modifier = ModifierRegistry.applyModifiers(props.indicator.modifiers, appContext, composableScope, globalEventDispatcher),
49
+ color = props.indicator.color.composeOrNull ?: MaterialTheme.colorScheme.primary,
50
+ containerColor = props.indicator.containerColor.composeOrNull ?: MaterialTheme.colorScheme.surfaceContainerHigh
34
51
  )
35
52
  },
36
53
  modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
@@ -34,6 +34,14 @@ class SlotView(context: Context, appContext: AppContext) :
34
34
  }
35
35
  }
36
36
 
37
+ /**
38
+ * Renders the slot content within a new [ComposableScope].
39
+ */
40
+ @Composable
41
+ fun SlotView.renderSlot() {
42
+ with(ComposableScope()) { with(this@renderSlot) { Content() } }
43
+ }
44
+
37
45
  fun isSlotWithName(view: ExpoComposeView<*>, slotName: String): Boolean {
38
46
  return view is SlotView && view.props.slotName.value == slotName
39
47
  }