@expo/ui 55.0.3 → 55.0.5

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 +17 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/BottomSheetView.kt +91 -13
  4. package/android/src/main/java/expo/modules/ui/CarouselView.kt +93 -67
  5. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +15 -6
  6. package/android/src/main/java/expo/modules/ui/TextInputView.kt +39 -15
  7. package/build/datetime-picker/DateTimePicker.android.d.ts +3 -0
  8. package/build/datetime-picker/DateTimePicker.android.d.ts.map +1 -0
  9. package/build/datetime-picker/DateTimePicker.d.ts +3 -0
  10. package/build/datetime-picker/DateTimePicker.d.ts.map +1 -0
  11. package/build/datetime-picker/DateTimePicker.web.d.ts +3 -0
  12. package/build/datetime-picker/DateTimePicker.web.d.ts.map +1 -0
  13. package/build/datetime-picker/index.d.ts +5 -0
  14. package/build/datetime-picker/index.d.ts.map +1 -0
  15. package/build/datetime-picker/types.d.ts +128 -0
  16. package/build/datetime-picker/types.d.ts.map +1 -0
  17. package/build/jetpack-compose/Carousel/index.d.ts +86 -23
  18. package/build/jetpack-compose/Carousel/index.d.ts.map +1 -1
  19. package/build/jetpack-compose/ModalBottomSheet/index.d.ts +65 -13
  20. package/build/jetpack-compose/ModalBottomSheet/index.d.ts.map +1 -1
  21. package/build/jetpack-compose/Progress/index.d.ts +6 -7
  22. package/build/jetpack-compose/Progress/index.d.ts.map +1 -1
  23. package/build/jetpack-compose/TextInput/index.d.ts +9 -0
  24. package/build/jetpack-compose/TextInput/index.d.ts.map +1 -1
  25. package/build/swift-ui/Link/index.d.ts +36 -0
  26. package/build/swift-ui/Link/index.d.ts.map +1 -0
  27. package/build/swift-ui/index.d.ts +1 -0
  28. package/build/swift-ui/index.d.ts.map +1 -1
  29. package/build/swift-ui/modifiers/environment.d.ts +16 -1
  30. package/build/swift-ui/modifiers/environment.d.ts.map +1 -1
  31. package/build/swift-ui/modifiers/index.d.ts +3 -7
  32. package/build/swift-ui/modifiers/index.d.ts.map +1 -1
  33. package/build/swift-ui/modifiers/widgets.d.ts +14 -0
  34. package/build/swift-ui/modifiers/widgets.d.ts.map +1 -0
  35. package/expo-module.config.json +1 -1
  36. package/ios/ExpoUIModule.swift +1 -0
  37. package/ios/LinkView.swift +29 -0
  38. package/ios/Modifiers/EnvironmentModifier.swift +14 -0
  39. package/ios/Modifiers/ViewModifierRegistry.swift +4 -0
  40. package/ios/Modifiers/WidgetModifiers.swift +12 -0
  41. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{55.0.3/expo.modules.ui-55.0.3-sources.jar → 55.0.5/expo.modules.ui-55.0.5-sources.jar} +0 -0
  42. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5-sources.jar.md5 +1 -0
  43. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5-sources.jar.sha1 +1 -0
  44. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5-sources.jar.sha256 +1 -0
  45. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5-sources.jar.sha512 +1 -0
  46. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.aar +0 -0
  47. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.aar.md5 +1 -0
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.aar.sha1 +1 -0
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.aar.sha256 +1 -0
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.aar.sha512 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{55.0.3/expo.modules.ui-55.0.3.module → 55.0.5/expo.modules.ui-55.0.5.module} +22 -22
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.module.md5 +1 -0
  53. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.module.sha1 +1 -0
  54. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.module.sha256 +1 -0
  55. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.module.sha512 +1 -0
  56. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{55.0.3/expo.modules.ui-55.0.3.pom → 55.0.5/expo.modules.ui-55.0.5.pom} +1 -1
  57. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.pom.md5 +1 -0
  58. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.pom.sha1 +1 -0
  59. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.pom.sha256 +1 -0
  60. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.5/expo.modules.ui-55.0.5.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 +6 -2
  67. package/src/datetime-picker/DateTimePicker.android.tsx +126 -0
  68. package/src/datetime-picker/DateTimePicker.tsx +94 -0
  69. package/src/datetime-picker/DateTimePicker.web.tsx +5 -0
  70. package/src/datetime-picker/index.tsx +11 -0
  71. package/src/datetime-picker/types.tsx +147 -0
  72. package/src/jetpack-compose/Carousel/index.tsx +118 -30
  73. package/src/jetpack-compose/ModalBottomSheet/index.tsx +85 -15
  74. package/src/jetpack-compose/Progress/index.tsx +7 -7
  75. package/src/jetpack-compose/TextInput/index.tsx +10 -0
  76. package/src/swift-ui/Link/index.tsx +52 -0
  77. package/src/swift-ui/index.tsx +1 -0
  78. package/src/swift-ui/modifiers/environment.ts +17 -4
  79. package/src/swift-ui/modifiers/index.ts +4 -10
  80. package/src/swift-ui/modifiers/widgets.ts +18 -0
  81. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3-sources.jar.md5 +0 -1
  82. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3-sources.jar.sha1 +0 -1
  83. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3-sources.jar.sha256 +0 -1
  84. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3-sources.jar.sha512 +0 -1
  85. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.aar +0 -0
  86. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.aar.md5 +0 -1
  87. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.aar.sha1 +0 -1
  88. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.aar.sha256 +0 -1
  89. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.aar.sha512 +0 -1
  90. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.module.md5 +0 -1
  91. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.module.sha1 +0 -1
  92. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.module.sha256 +0 -1
  93. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.module.sha512 +0 -1
  94. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.pom.md5 +0 -1
  95. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.pom.sha1 +0 -1
  96. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.pom.sha256 +0 -1
  97. package/local-maven-repo/expo/modules/ui/expo.modules.ui/55.0.3/expo.modules.ui-55.0.3.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,19 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 55.0.5 — 2026-03-19
14
+
15
+ ### 🛠 Breaking changes
16
+
17
+ - [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))
18
+
19
+ ## 55.0.4 — 2026-03-18
20
+
21
+ ### 🎉 New features
22
+
23
+ - [iOS] Add `Link` view. ([#43983](https://github.com/expo/expo/pull/43983) by [@jakex7](https://github.com/jakex7))
24
+ - [iOS] Add `widgetURL` modifier. ([#43984](https://github.com/expo/expo/pull/43984) by [@jakex7](https://github.com/jakex7))
25
+
13
26
  ## 55.0.3 — 2026-03-17
14
27
 
15
28
  ### 🛠 Breaking changes
@@ -30,6 +43,10 @@
30
43
 
31
44
  ### 🎉 New features
32
45
 
46
+ - [android] Added `outlined` variant to `TextInput` component. ([#43719](https://github.com/expo/expo/pull/43719) by [@benjaminkomen](https://github.com/benjaminkomen))
47
+ - 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))
48
+ - [iOS] Added `locale` and `timeZone` support to `modifiers`. ([#44013](https://github.com/expo/expo/pull/44013) by [@vonovak](https://github.com/vonovak))
49
+ - [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))
33
50
  - [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))
34
51
  - [android] Added `Checkbox` and `TriStateCheckbox` components. ([#43887](https://github.com/expo/expo/pull/43887) by [@nishan](https://github.com/intergalacticspacehighway))
35
52
  - [Android] Added `DatePickerDialog` and `TimePickerDialog` components, and `selectableDates` prop to `DateTimePicker`. ([#43895](https://github.com/expo/expo/pull/43895) by [@vonovak](https://github.com/vonovak))
@@ -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.3'
15
+ version = '55.0.5'
16
16
 
17
17
  android {
18
18
  namespace "expo.modules.ui"
19
19
  defaultConfig {
20
20
  versionCode 1
21
- versionName "55.0.3"
21
+ versionName "55.0.5"
22
22
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
23
23
  }
24
24
  buildFeatures {
@@ -2,28 +2,106 @@
2
2
 
3
3
  package expo.modules.ui
4
4
 
5
+ import android.annotation.SuppressLint
6
+ import android.content.Context
7
+ import android.graphics.Color
8
+ import androidx.compose.material3.BottomSheetDefaults
5
9
  import androidx.compose.material3.ExperimentalMaterial3Api
6
10
  import androidx.compose.material3.ModalBottomSheet
11
+ import androidx.compose.material3.ModalBottomSheetProperties
12
+ import androidx.compose.material3.SheetState
13
+ import androidx.compose.material3.contentColorFor
7
14
  import androidx.compose.material3.rememberModalBottomSheetState
8
15
  import androidx.compose.runtime.Composable
16
+ import androidx.compose.runtime.MutableState
17
+ import androidx.compose.runtime.mutableStateOf
18
+ import androidx.compose.runtime.rememberCoroutineScope
19
+ import kotlin.coroutines.cancellation.CancellationException
20
+ import kotlinx.coroutines.CoroutineScope
21
+ import kotlinx.coroutines.withContext
22
+ import expo.modules.kotlin.AppContext
23
+ import expo.modules.kotlin.records.Field
24
+ import expo.modules.kotlin.records.Record
25
+ import expo.modules.kotlin.viewevent.EventDispatcher
9
26
  import expo.modules.kotlin.views.ComposableScope
10
27
  import expo.modules.kotlin.views.ComposeProps
11
- import expo.modules.kotlin.views.FunctionalComposableScope
28
+ import expo.modules.kotlin.views.ExpoComposeView
12
29
 
13
- data class ModalBottomSheetProps(
14
- val skipPartiallyExpanded: Boolean = false,
15
- val modifiers: ModifierList = emptyList()
30
+ data class ModalBottomSheetPropertiesRecord(
31
+ @Field val shouldDismissOnBackPress: Boolean = true,
32
+ @Field val shouldDismissOnClickOutside: Boolean = true
33
+ ) : Record
34
+
35
+ data class ModalBottomSheetViewProps(
36
+ val skipPartiallyExpanded: MutableState<Boolean> = mutableStateOf(false),
37
+ val containerColor: MutableState<Color?> = mutableStateOf(null),
38
+ val contentColor: MutableState<Color?> = mutableStateOf(null),
39
+ val scrimColor: MutableState<Color?> = mutableStateOf(null),
40
+ val showDragHandle: MutableState<Boolean> = mutableStateOf(true),
41
+ val sheetGesturesEnabled: MutableState<Boolean> = mutableStateOf(true),
42
+ val properties: MutableState<ModalBottomSheetPropertiesRecord> = mutableStateOf(ModalBottomSheetPropertiesRecord()),
43
+ val modifiers: MutableState<ModifierList> = mutableStateOf(emptyList())
16
44
  ) : ComposeProps
17
45
 
18
- @Composable
19
- fun FunctionalComposableScope.ModalBottomSheetContent(props: ModalBottomSheetProps, onDismissRequest: () -> Unit) {
20
- val sheetState = rememberModalBottomSheetState(props.skipPartiallyExpanded)
46
+ @SuppressLint("ViewConstructor")
47
+ class ModalBottomSheetView(context: Context, appContext: AppContext) :
48
+ ExpoComposeView<ModalBottomSheetViewProps>(context, appContext) {
49
+ override val props = ModalBottomSheetViewProps()
50
+ internal val onDismissRequest by EventDispatcher<Unit>()
51
+
52
+ internal var sheetState: SheetState? = null
53
+ private var composeScope: CoroutineScope? = null
54
+
55
+ suspend fun hide() {
56
+ val scope = composeScope ?: return
57
+ val state = sheetState ?: return
58
+ try {
59
+ withContext(scope.coroutineContext) {
60
+ state.hide()
61
+ }
62
+ } catch (_: CancellationException) {
63
+ // Swipe-dismiss may cancel the coroutine scope while hide() is in-flight.
64
+ // Swallowing the exception avoids an unhandled promise rejection on the JS side.
65
+ }
66
+ }
67
+
68
+ @Composable
69
+ override fun ComposableScope.Content() {
70
+ val sheetState = rememberModalBottomSheetState(props.skipPartiallyExpanded.value)
71
+ val scope = rememberCoroutineScope()
72
+ this@ModalBottomSheetView.sheetState = sheetState
73
+ this@ModalBottomSheetView.composeScope = scope
74
+
75
+ val resolvedContainerColor = props.containerColor.value.composeOrNull ?: BottomSheetDefaults.ContainerColor
76
+ val resolvedContentColor = props.contentColor.value.composeOrNull ?: contentColorFor(resolvedContainerColor)
77
+ val resolvedScrimColor = props.scrimColor.value.composeOrNull ?: BottomSheetDefaults.ScrimColor
78
+ val dragHandleSlotView = findChildSlotView(this@ModalBottomSheetView, "dragHandle")
21
79
 
22
- ModalBottomSheet(
23
- sheetState = sheetState,
24
- onDismissRequest = { onDismissRequest() },
25
- modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
26
- ) {
27
- Children(ComposableScope())
80
+ ModalBottomSheet(
81
+ sheetState = sheetState,
82
+ onDismissRequest = {
83
+ onDismissRequest(Unit)
84
+ },
85
+ containerColor = resolvedContainerColor,
86
+ contentColor = resolvedContentColor,
87
+ scrimColor = resolvedScrimColor,
88
+ sheetGesturesEnabled = props.sheetGesturesEnabled.value,
89
+ dragHandle = when {
90
+ dragHandleSlotView != null -> {
91
+ { with(ComposableScope()) { with(dragHandleSlotView) { Content() } } }
92
+ }
93
+ props.showDragHandle.value -> {
94
+ { BottomSheetDefaults.DragHandle() }
95
+ }
96
+ else -> null
97
+ },
98
+ properties = ModalBottomSheetProperties(
99
+ shouldDismissOnBackPress = props.properties.value.shouldDismissOnBackPress,
100
+ shouldDismissOnClickOutside = props.properties.value.shouldDismissOnClickOutside
101
+ ),
102
+ modifier = ModifierRegistry.applyModifiers(props.modifiers.value, appContext, this@Content, globalEventDispatcher)
103
+ ) {
104
+ Children(ComposableScope(), filter = { !isSlotView(it) })
105
+ }
28
106
  }
29
107
  }
@@ -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
  }
@@ -6,6 +6,7 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
6
6
  import androidx.compose.material3.SwitchDefaults
7
7
  import androidx.compose.material3.ToggleButtonDefaults
8
8
  import androidx.compose.runtime.remember
9
+ import expo.modules.kotlin.functions.Coroutine
9
10
  import expo.modules.kotlin.modules.Module
10
11
  import expo.modules.kotlin.modules.ModuleDefinition
11
12
  import expo.modules.kotlin.viewevent.getValue
@@ -92,11 +93,11 @@ class ExpoUIModule : Module() {
92
93
 
93
94
  //region Expo UI views
94
95
 
95
- ExpoUIView("ModalBottomSheetView", events = {
96
+ View(ModalBottomSheetView::class) {
96
97
  Events("onDismissRequest")
97
- }) { props: ModalBottomSheetProps ->
98
- val onDismissRequest by remember { EventDispatcher<Unit>() }
99
- ModalBottomSheetContent(props) { onDismissRequest(Unit) }
98
+ AsyncFunction("hide") Coroutine { view: ModalBottomSheetView ->
99
+ view.hide()
100
+ }
100
101
  }
101
102
 
102
103
  ExpoUIView("SingleChoiceSegmentedButtonRowView") { props: SingleChoiceSegmentedButtonRowProps ->
@@ -311,8 +312,16 @@ class ExpoUIModule : Module() {
311
312
  PullToRefreshBoxContent(props) { onRefresh(Unit) }
312
313
  }
313
314
 
314
- ExpoUIView("CarouselView") { props: CarouselProps ->
315
- CarouselContent(props)
315
+ ExpoUIView("HorizontalCenteredHeroCarouselView") { props: HorizontalCenteredHeroCarouselProps ->
316
+ HorizontalCenteredHeroCarouselContent(props)
317
+ }
318
+
319
+ ExpoUIView("HorizontalMultiBrowseCarouselView") { props: HorizontalMultiBrowseCarouselProps ->
320
+ HorizontalMultiBrowseCarouselContent(props)
321
+ }
322
+
323
+ ExpoUIView("HorizontalUncontainedCarouselView") { props: HorizontalUncontainedCarouselProps ->
324
+ HorizontalUncontainedCarouselContent(props)
316
325
  }
317
326
 
318
327
  ExpoUIView("AlertDialogView", events = {
@@ -1,7 +1,9 @@
1
1
  package expo.modules.ui
2
2
 
3
+ import android.annotation.SuppressLint
3
4
  import android.content.Context
4
5
  import androidx.compose.foundation.text.KeyboardOptions
6
+ import androidx.compose.material3.OutlinedTextField
5
7
  import androidx.compose.material3.Text
6
8
  import androidx.compose.material3.TextField
7
9
  import androidx.compose.runtime.Composable
@@ -18,6 +20,7 @@ import expo.modules.kotlin.views.ExpoComposeView
18
20
  data class TextInputProps(
19
21
  val defaultValue: MutableState<String> = mutableStateOf(""),
20
22
  val placeholder: MutableState<String> = mutableStateOf(""),
23
+ val variant: MutableState<String> = mutableStateOf("filled"),
21
24
  val multiline: MutableState<Boolean> = mutableStateOf(false),
22
25
  val numberOfLines: MutableState<Int?> = mutableStateOf(null),
23
26
  val keyboardType: MutableState<String> = mutableStateOf("default"),
@@ -52,6 +55,7 @@ private fun String.autoCapitalize(): KeyboardCapitalization {
52
55
  }
53
56
  }
54
57
 
58
+ @SuppressLint("ViewConstructor")
55
59
  class TextInputView(context: Context, appContext: AppContext) :
56
60
  ExpoComposeView<TextInputProps>(context, appContext) {
57
61
  override val props = TextInputProps()
@@ -68,21 +72,41 @@ class TextInputView(context: Context, appContext: AppContext) :
68
72
 
69
73
  @Composable
70
74
  override fun ComposableScope.Content() {
71
- TextField(
72
- value = requireNotNull(textState.value),
73
- onValueChange = {
74
- textState.value = it
75
- onValueChanged(mapOf("value" to it))
76
- },
77
- placeholder = { Text(props.placeholder.value) },
78
- maxLines = if (props.multiline.value) props.numberOfLines.value ?: Int.MAX_VALUE else 1,
79
- singleLine = !props.multiline.value,
80
- keyboardOptions = KeyboardOptions.Default.copy(
81
- keyboardType = props.keyboardType.value.keyboardType(),
82
- autoCorrectEnabled = props.autocorrection.value,
83
- capitalization = props.autoCapitalize.value.autoCapitalize()
84
- ),
85
- modifier = ModifierRegistry.applyModifiers(props.modifiers.value, appContext, this@Content, globalEventDispatcher)
75
+ val value = textState.value ?: props.defaultValue.value
76
+ val onValueChange: (String) -> Unit = {
77
+ textState.value = it
78
+ onValueChanged(mapOf("value" to it))
79
+ }
80
+ val placeholder: @Composable () -> Unit = { Text(props.placeholder.value) }
81
+ val maxLines = if (props.multiline.value) props.numberOfLines.value ?: Int.MAX_VALUE else 1
82
+ val singleLine = !props.multiline.value
83
+ val keyboardOptions = KeyboardOptions.Default.copy(
84
+ keyboardType = props.keyboardType.value.keyboardType(),
85
+ autoCorrectEnabled = props.autocorrection.value,
86
+ capitalization = props.autoCapitalize.value.autoCapitalize()
86
87
  )
88
+ val modifier = ModifierRegistry.applyModifiers(props.modifiers.value, appContext, this@Content, globalEventDispatcher)
89
+
90
+ if (props.variant.value == "outlined") {
91
+ OutlinedTextField(
92
+ value = value,
93
+ onValueChange = onValueChange,
94
+ placeholder = placeholder,
95
+ maxLines = maxLines,
96
+ singleLine = singleLine,
97
+ keyboardOptions = keyboardOptions,
98
+ modifier = modifier
99
+ )
100
+ } else {
101
+ TextField(
102
+ value = value,
103
+ onValueChange = onValueChange,
104
+ placeholder = placeholder,
105
+ maxLines = maxLines,
106
+ singleLine = singleLine,
107
+ keyboardOptions = keyboardOptions,
108
+ modifier = modifier
109
+ )
110
+ }
87
111
  }
88
112
  }
@@ -0,0 +1,3 @@
1
+ import { type DateTimePickerProps } from './types';
2
+ export declare function DateTimePicker(props: DateTimePickerProps): import("react").JSX.Element;
3
+ //# sourceMappingURL=DateTimePicker.android.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateTimePicker.android.d.ts","sourceRoot":"","sources":["../../src/datetime-picker/DateTimePicker.android.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAmCjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BA0FxD"}
@@ -0,0 +1,3 @@
1
+ import { type DateTimePickerProps } from './types';
2
+ export declare function DateTimePicker(props: DateTimePickerProps): import("react").JSX.Element;
3
+ //# sourceMappingURL=DateTimePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateTimePicker.d.ts","sourceRoot":"","sources":["../../src/datetime-picker/DateTimePicker.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAoCjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BAyDxD"}
@@ -0,0 +1,3 @@
1
+ import type { DateTimePickerProps } from './types';
2
+ export declare function DateTimePicker(_props: DateTimePickerProps): null;
3
+ //# sourceMappingURL=DateTimePicker.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateTimePicker.web.d.ts","sourceRoot":"","sources":["../../src/datetime-picker/DateTimePicker.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,wBAAgB,cAAc,CAAC,MAAM,EAAE,mBAAmB,QAEzD"}
@@ -0,0 +1,5 @@
1
+ import { DateTimePicker } from './DateTimePicker';
2
+ export { type DateTimePickerEvent, type DateTimePickerChangeEvent, type DateTimePickerProps, } from './types';
3
+ export default DateTimePicker;
4
+ export { DateTimePicker };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/datetime-picker/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,GACzB,MAAM,SAAS,CAAC;AAEjB,eAAe,cAAc,CAAC;AAE9B,OAAO,EAAE,cAAc,EAAE,CAAC"}