@expo/ui 58.0.8 → 58.0.9

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 (119) hide show
  1. package/CHANGELOG.md +6 -7
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/AnimatedVisibilityView.kt +40 -8
  4. package/android/src/main/java/expo/modules/ui/ComposeViews.kt +21 -3
  5. package/android/src/main/java/expo/modules/ui/DatePickerView.kt +12 -4
  6. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +5 -1
  7. package/android/src/main/java/expo/modules/ui/HorizontalPagerView.kt +3 -1
  8. package/android/src/main/java/expo/modules/ui/HostView.kt +64 -12
  9. package/android/src/main/java/expo/modules/ui/LazyItemsView.kt +14 -2
  10. package/android/src/main/java/expo/modules/ui/ModalBottomSheetView.kt +5 -1
  11. package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +29 -4
  12. package/android/src/main/java/expo/modules/ui/RNHostView.kt +3 -1
  13. package/android/src/main/java/expo/modules/ui/ShapeView.kt +3 -1
  14. package/android/src/main/java/expo/modules/ui/SlotView.kt +3 -1
  15. package/android/src/main/java/expo/modules/ui/SnackbarView.kt +5 -1
  16. package/android/src/main/java/expo/modules/ui/TextView.kt +3 -1
  17. package/android/src/main/java/expo/modules/ui/Utils.kt +3 -1
  18. package/android/src/main/java/expo/modules/ui/colors/MaterialColors.kt +5 -1
  19. package/android/src/main/java/expo/modules/ui/convertibles/AnimationSpecParams.kt +3 -1
  20. package/android/src/main/java/expo/modules/ui/graphics/ImageLoader.kt +6 -2
  21. package/android/src/main/java/expo/modules/ui/icon/IconView.kt +5 -1
  22. package/android/src/main/java/expo/modules/ui/state/ObservableState.kt +3 -1
  23. package/android/src/main/java/expo/modules/ui/textfield/BasicTextField.kt +10 -2
  24. package/android/src/main/java/expo/modules/ui/textfield/TextField.kt +20 -4
  25. package/android/src/main/java/expo/modules/ui/textfield/TextFieldShared.kt +3 -1
  26. package/build/jetpack-compose/LazyColumn/index.d.ts +2 -1
  27. package/build/jetpack-compose/LazyColumn/index.js +1 -0
  28. package/build/jetpack-compose/LazyColumn/index.js.map +1 -1
  29. package/build/jetpack-compose/LazyItems/index.d.ts +19 -18
  30. package/build/jetpack-compose/LazyItems/index.js +1 -2
  31. package/build/jetpack-compose/LazyItems/index.js.map +1 -1
  32. package/build/jetpack-compose/LazyRow/index.d.ts +2 -1
  33. package/build/jetpack-compose/LazyRow/index.js +1 -0
  34. package/build/jetpack-compose/LazyRow/index.js.map +1 -1
  35. package/build/jetpack-compose/index.d.ts +0 -1
  36. package/build/jetpack-compose/index.js.map +1 -1
  37. package/build/jetpack-compose/modifiers/index.d.ts +18 -3
  38. package/build/jetpack-compose/modifiers/index.js +15 -2
  39. package/build/jetpack-compose/modifiers/index.js.map +1 -1
  40. package/build/swift-ui/LazyHStack/index.d.ts +45 -0
  41. package/build/swift-ui/LazyHStack/index.js +9 -0
  42. package/build/swift-ui/LazyHStack/index.js.map +1 -1
  43. package/build/swift-ui/LazyStackForEach/index.d.ts +44 -0
  44. package/build/swift-ui/LazyStackForEach/index.js +54 -0
  45. package/build/swift-ui/LazyStackForEach/index.js.map +1 -0
  46. package/build/swift-ui/LazyVStack/index.d.ts +45 -0
  47. package/build/swift-ui/LazyVStack/index.js +9 -0
  48. package/build/swift-ui/LazyVStack/index.js.map +1 -1
  49. package/build/swift-ui/List/DataListForEach.d.ts +6 -7
  50. package/build/swift-ui/List/DataListForEach.js.map +1 -1
  51. package/build/swift-ui/List/ListForEach.d.ts +7 -1
  52. package/build/swift-ui/List/ListForEach.js +1 -5
  53. package/build/swift-ui/List/ListForEach.js.map +1 -1
  54. package/build/swift-ui/index.d.ts +1 -0
  55. package/build/swift-ui/index.js.map +1 -1
  56. package/build/universal/Switch/index.android.js +5 -1
  57. package/build/universal/Switch/index.android.js.map +1 -1
  58. package/expo-module.config.json +0 -1
  59. package/ios/DataListForEachView.swift +65 -28
  60. package/ios/LazyHStackView.swift +3 -0
  61. package/ios/LazyVStackView.swift +3 -0
  62. package/ios/ListView.swift +8 -0
  63. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.8/expo.modules.ui-58.0.8-sources.jar → 58.0.9/expo.modules.ui-58.0.9-sources.jar} +0 -0
  64. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.md5 +1 -0
  65. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha1 +1 -0
  66. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha256 +1 -0
  67. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha512 +1 -0
  68. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar +0 -0
  69. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.md5 +1 -0
  70. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha1 +1 -0
  71. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha256 +1 -0
  72. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha512 +1 -0
  73. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.8/expo.modules.ui-58.0.8.module → 58.0.9/expo.modules.ui-58.0.9.module} +22 -22
  74. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.md5 +1 -0
  75. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha1 +1 -0
  76. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha256 +1 -0
  77. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha512 +1 -0
  78. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.8/expo.modules.ui-58.0.8.pom → 58.0.9/expo.modules.ui-58.0.9.pom} +1 -1
  79. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.md5 +1 -0
  80. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha1 +1 -0
  81. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha256 +1 -0
  82. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha512 +1 -0
  83. package/package.json +3 -3
  84. package/prebuilds/output/debug/xcframeworks/ExpoUI.tar.gz +0 -0
  85. package/prebuilds/output/release/xcframeworks/ExpoUI.tar.gz +0 -0
  86. package/src/jetpack-compose/LazyColumn/index.tsx +2 -0
  87. package/src/jetpack-compose/LazyItems/index.tsx +18 -21
  88. package/src/jetpack-compose/LazyRow/index.tsx +2 -0
  89. package/src/jetpack-compose/index.ts +0 -1
  90. package/src/jetpack-compose/modifiers/index.ts +16 -3
  91. package/src/swift-ui/LazyHStack/index.tsx +45 -0
  92. package/src/swift-ui/LazyStackForEach/index.tsx +110 -0
  93. package/src/swift-ui/LazyVStack/index.tsx +45 -0
  94. package/src/swift-ui/List/DataListForEach.tsx +7 -8
  95. package/src/swift-ui/List/ListForEach.tsx +10 -3
  96. package/src/swift-ui/index.tsx +1 -0
  97. package/src/universal/Switch/index.android.tsx +11 -2
  98. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8-sources.jar.md5 +0 -1
  99. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8-sources.jar.sha1 +0 -1
  100. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8-sources.jar.sha256 +0 -1
  101. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8-sources.jar.sha512 +0 -1
  102. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar +0 -0
  103. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar.md5 +0 -1
  104. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar.sha1 +0 -1
  105. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar.sha256 +0 -1
  106. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar.sha512 +0 -1
  107. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.module.md5 +0 -1
  108. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.module.sha1 +0 -1
  109. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.module.sha256 +0 -1
  110. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.module.sha512 +0 -1
  111. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.pom.md5 +0 -1
  112. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.pom.sha1 +0 -1
  113. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.pom.sha256 +0 -1
  114. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.pom.sha512 +0 -1
  115. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +0 -13
  116. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +0 -1
  117. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +0 -1
  118. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +0 -1
  119. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -1,14 +1,13 @@
1
1
  # Changelog
2
2
 
3
- ## Unpublished
3
+ ## 58.0.9
4
4
 
5
- ### 🛠 Breaking changes
6
-
7
- ### 🎉 New features
5
+ ### Patch Changes
8
6
 
9
- ### 🐛 Bug fixes
10
-
11
- ### 💡 Others
7
+ - Force-bump all packages, due to migration to changesets. ([#50762](https://github.com/expo/expo/pull/50762) by [@kitten](https://github.com/kitten))
8
+ - [iOS] Added `LazyVStack.ForEach` and `LazyHStack.ForEach`, which render rows from `data` and `keyExtractor` with a `children` function: `{({ item, index }) => <Row item={item} />}`. Rows are recycled from a small pool around the visible range, so large stacks only render the rows near the viewport. Set `recycling={false}` to render every row. ([#50579](https://github.com/expo/expo/pull/50579) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
9
+ - [android] Fix `Switch` label rendering one letter per line inside a `Host` with `matchContents`. ([#50693](https://github.com/expo/expo/pull/50693) by [@janicduplessis](https://github.com/janicduplessis))
10
+ - [android] Added `IntrinsicSize` support to the `width` modifier. ([#50693](https://github.com/expo/expo/pull/50693) by [@janicduplessis](https://github.com/janicduplessis))
12
11
 
13
12
  ## 58.0.8 — 2026-09-28
14
13
 
@@ -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 = '58.0.8'
15
+ version = '58.0.9'
16
16
 
17
17
  android {
18
18
  namespace "expo.modules.ui"
19
19
  defaultConfig {
20
20
  versionCode 1
21
- versionName "58.0.8"
21
+ versionName "58.0.9"
22
22
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
23
23
  }
24
24
  buildFeatures {
@@ -73,32 +73,64 @@ data class ExitTransitionRecord(
73
73
  // TODO(@ubax): expose animationSpec parameter (tween, spring, duration) for all transitions
74
74
  private fun EnterTransitionRecord.toComposeTransition(): EnterTransition = when (type) {
75
75
  EnterTransitionType.FADE_IN ->
76
- if (initialAlpha != null) fadeIn(initialAlpha = initialAlpha) else fadeIn()
76
+ if (initialAlpha != null) {
77
+ fadeIn(initialAlpha = initialAlpha)
78
+ } else {
79
+ fadeIn()
80
+ }
77
81
  EnterTransitionType.SLIDE_IN_HORIZONTALLY ->
78
- if (initialOffsetX != null) slideInHorizontally { (it * initialOffsetX).toInt() } else slideInHorizontally()
82
+ if (initialOffsetX != null) {
83
+ slideInHorizontally { (it * initialOffsetX).toInt() }
84
+ } else {
85
+ slideInHorizontally()
86
+ }
79
87
  EnterTransitionType.SLIDE_IN_VERTICALLY ->
80
- if (initialOffsetY != null) slideInVertically { (it * initialOffsetY).toInt() } else slideInVertically()
88
+ if (initialOffsetY != null) {
89
+ slideInVertically { (it * initialOffsetY).toInt() }
90
+ } else {
91
+ slideInVertically()
92
+ }
81
93
  // TODO(@ubax): expose expandFrom (Alignment) and initialSize parameters for expand transitions
82
94
  EnterTransitionType.EXPAND_IN -> expandIn()
83
95
  EnterTransitionType.EXPAND_HORIZONTALLY -> expandHorizontally()
84
96
  EnterTransitionType.EXPAND_VERTICALLY -> expandVertically()
85
97
  EnterTransitionType.SCALE_IN ->
86
- if (initialScale != null) scaleIn(initialScale = initialScale) else scaleIn()
98
+ if (initialScale != null) {
99
+ scaleIn(initialScale = initialScale)
100
+ } else {
101
+ scaleIn()
102
+ }
87
103
  }
88
104
 
89
105
  private fun ExitTransitionRecord.toComposeTransition(): ExitTransition = when (type) {
90
106
  ExitTransitionType.FADE_OUT ->
91
- if (targetAlpha != null) fadeOut(targetAlpha = targetAlpha) else fadeOut()
107
+ if (targetAlpha != null) {
108
+ fadeOut(targetAlpha = targetAlpha)
109
+ } else {
110
+ fadeOut()
111
+ }
92
112
  ExitTransitionType.SLIDE_OUT_HORIZONTALLY ->
93
- if (targetOffsetX != null) slideOutHorizontally { (it * targetOffsetX).toInt() } else slideOutHorizontally()
113
+ if (targetOffsetX != null) {
114
+ slideOutHorizontally { (it * targetOffsetX).toInt() }
115
+ } else {
116
+ slideOutHorizontally()
117
+ }
94
118
  ExitTransitionType.SLIDE_OUT_VERTICALLY ->
95
- if (targetOffsetY != null) slideOutVertically { (it * targetOffsetY).toInt() } else slideOutVertically()
119
+ if (targetOffsetY != null) {
120
+ slideOutVertically { (it * targetOffsetY).toInt() }
121
+ } else {
122
+ slideOutVertically()
123
+ }
96
124
  // TODO(@ubax): expose shrinkTowards (Alignment) and targetSize parameters for shrink transitions
97
125
  ExitTransitionType.SHRINK_OUT -> shrinkOut()
98
126
  ExitTransitionType.SHRINK_HORIZONTALLY -> shrinkHorizontally()
99
127
  ExitTransitionType.SHRINK_VERTICALLY -> shrinkVertically()
100
128
  ExitTransitionType.SCALE_OUT ->
101
- if (targetScale != null) scaleOut(targetScale = targetScale) else scaleOut()
129
+ if (targetScale != null) {
130
+ scaleOut(targetScale = targetScale)
131
+ } else {
132
+ scaleOut()
133
+ }
102
134
  }
103
135
 
104
136
  private fun List<EnterTransitionRecord>.toComposedEnterTransition(): EnterTransition? =
@@ -65,7 +65,13 @@ internal fun FunctionalComposableScope.RowContent(props: LayoutProps) {
65
65
  verticalAlignment = props.verticalAlignment?.toComposeAlignment() ?: Alignment.Top,
66
66
  modifier = ModifierRegistry
67
67
  .applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
68
- .then(if (scrollBehavior != null) Modifier.nestedScroll(scrollBehavior) else Modifier)
68
+ .then(
69
+ if (scrollBehavior != null) {
70
+ Modifier.nestedScroll(scrollBehavior)
71
+ } else {
72
+ Modifier
73
+ }
74
+ )
69
75
  ) {
70
76
  Children(UIComposableScope(rowScope = this@Row, nestedScrollConnection = scrollBehavior))
71
77
  }
@@ -95,7 +101,13 @@ internal fun FunctionalComposableScope.ColumnContent(props: LayoutProps) {
95
101
  horizontalAlignment = props.horizontalAlignment?.toComposeAlignment() ?: Alignment.Start,
96
102
  modifier = ModifierRegistry
97
103
  .applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
98
- .then(if (scrollBehavior != null) Modifier.nestedScroll(scrollBehavior) else Modifier)
104
+ .then(
105
+ if (scrollBehavior != null) {
106
+ Modifier.nestedScroll(scrollBehavior)
107
+ } else {
108
+ Modifier
109
+ }
110
+ )
99
111
  ) {
100
112
  Children(UIComposableScope(columnScope = this@Column, nestedScrollConnection = scrollBehavior))
101
113
  }
@@ -112,7 +124,13 @@ fun FunctionalComposableScope.BoxContent(props: LayoutProps) {
112
124
  contentAlignment = props.contentAlignment?.toComposeAlignment() ?: Alignment.TopStart,
113
125
  modifier = ModifierRegistry
114
126
  .applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
115
- .then(if (scrollBehavior != null) Modifier.nestedScroll(scrollBehavior) else Modifier)
127
+ .then(
128
+ if (scrollBehavior != null) {
129
+ Modifier.nestedScroll(scrollBehavior)
130
+ } else {
131
+ Modifier
132
+ }
133
+ )
116
134
  ) {
117
135
  Children(UIComposableScope(boxScope = this@Box, nestedScrollConnection = scrollBehavior))
118
136
  }
@@ -219,14 +219,22 @@ fun rememberSelectableDates(selectableDatesRecord: SelectableDatesRecord?): Sele
219
219
 
220
220
  object : SelectableDates {
221
221
  override fun isSelectableDate(utcTimeMillis: Long): Boolean {
222
- if (startUtcDayMillis != null && utcTimeMillis < startUtcDayMillis) return false
223
- if (endUtcDayMillis != null && utcTimeMillis > endUtcDayMillis) return false
222
+ if (startUtcDayMillis != null && utcTimeMillis < startUtcDayMillis) {
223
+ return false
224
+ }
225
+ if (endUtcDayMillis != null && utcTimeMillis > endUtcDayMillis) {
226
+ return false
227
+ }
224
228
  return true
225
229
  }
226
230
 
227
231
  override fun isSelectableYear(year: Int): Boolean {
228
- if (startYear != null && year < startYear) return false
229
- if (endYear != null && year > endYear) return false
232
+ if (startYear != null && year < startYear) {
233
+ return false
234
+ }
235
+ if (endYear != null && year > endYear) {
236
+ return false
237
+ }
230
238
  return true
231
239
  }
232
240
  }
@@ -167,7 +167,11 @@ class ExpoUIModule : Module() {
167
167
  ?: appContext.reactContext
168
168
  ?: throw Exceptions.ReactContextLost()
169
169
  val resolvedScheme = options?.scheme
170
- ?: if (context.isSystemInDarkTheme()) ExpoColorScheme.DARK else ExpoColorScheme.LIGHT
170
+ ?: if (context.isSystemInDarkTheme()) {
171
+ ExpoColorScheme.DARK
172
+ } else {
173
+ ExpoColorScheme.LIGHT
174
+ }
171
175
  val isDark = resolvedScheme == ExpoColorScheme.DARK
172
176
  val seedArgb = options?.seedColor?.composeOrNull?.toArgb()
173
177
  val colorScheme = if (seedArgb != null) {
@@ -125,7 +125,9 @@ fun FunctionalComposableScope.HorizontalPagerContent(
125
125
  }
126
126
 
127
127
  val pageCount = pageCountState.intValue
128
- if (pageCount == 0) return
128
+ if (pageCount == 0) {
129
+ return
130
+ }
129
131
 
130
132
  // Mirror Compose's PagerState observable fields to JS callbacks. Each
131
133
  // state-backed snapshotFlow drops its first emission so we don't echo the
@@ -81,17 +81,33 @@ internal enum class ExpoColorScheme(val value: String) : Enumerable {
81
81
 
82
82
  fun toColorScheme(context: Context): ColorScheme {
83
83
  return when (this) {
84
- LIGHT -> if (isDynamicColorSupported) dynamicLightColorScheme(context) else lightColorScheme()
85
- DARK -> if (isDynamicColorSupported) dynamicDarkColorScheme(context) else darkColorScheme()
84
+ LIGHT -> if (isDynamicColorSupported) {
85
+ dynamicLightColorScheme(context)
86
+ } else {
87
+ lightColorScheme()
88
+ }
89
+ DARK -> if (isDynamicColorSupported) {
90
+ dynamicDarkColorScheme(context)
91
+ } else {
92
+ darkColorScheme()
93
+ }
86
94
  }
87
95
  }
88
96
 
89
97
  companion object {
90
98
  fun defaultColorScheme(context: Context, isSystemInDarkTheme: Boolean): ColorScheme {
91
99
  return if (isDynamicColorSupported) {
92
- if (isSystemInDarkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
100
+ if (isSystemInDarkTheme) {
101
+ dynamicDarkColorScheme(context)
102
+ } else {
103
+ dynamicLightColorScheme(context)
104
+ }
93
105
  } else {
94
- if (isSystemInDarkTheme) darkColorScheme() else lightColorScheme()
106
+ if (isSystemInDarkTheme) {
107
+ darkColorScheme()
108
+ } else {
109
+ lightColorScheme()
110
+ }
95
111
  }
96
112
  }
97
113
  }
@@ -159,8 +175,20 @@ internal class HostView(context: Context, appContext: AppContext) :
159
175
 
160
176
  Layout(
161
177
  modifier = Modifier
162
- .then(if (props.matchContentsHorizontal.value == true) Modifier.wrapContentWidth() else Modifier)
163
- .then(if (props.matchContentsVertical.value == true) Modifier.wrapContentHeight() else Modifier)
178
+ .then(
179
+ if (props.matchContentsHorizontal.value == true) {
180
+ Modifier.wrapContentWidth()
181
+ } else {
182
+ Modifier
183
+ }
184
+ )
185
+ .then(
186
+ if (props.matchContentsVertical.value == true) {
187
+ Modifier.wrapContentHeight()
188
+ } else {
189
+ Modifier
190
+ }
191
+ )
164
192
  .onSizeChanged { size -> dispatchOnLayoutContent(size, density) },
165
193
  content = content
166
194
  ) { measurables, constraints ->
@@ -199,8 +227,16 @@ internal class HostView(context: Context, appContext: AppContext) :
199
227
  val heightDp = contentHeightPx.toDp().value.toDouble()
200
228
 
201
229
  shadowNodeProxy.setViewSize(
202
- if (constraints.maxWidth == 0) widthDp else Double.NaN,
203
- if (constraints.maxHeight == 0) heightDp else Double.NaN
230
+ if (constraints.maxWidth == 0) {
231
+ widthDp
232
+ } else {
233
+ Double.NaN
234
+ },
235
+ if (constraints.maxHeight == 0) {
236
+ heightDp
237
+ } else {
238
+ Double.NaN
239
+ }
204
240
  )
205
241
  }
206
242
  }
@@ -227,8 +263,16 @@ internal class HostView(context: Context, appContext: AppContext) :
227
263
  val height = size.height.toDp().value
228
264
 
229
265
  if (matchContentsHorizontal == true || matchContentsVertical == true) {
230
- val styleWidth = if (matchContentsHorizontal == true && width > 0) width else null
231
- val styleHeight = if (matchContentsVertical == true && height > 0) height else null
266
+ val styleWidth = if (matchContentsHorizontal == true && width > 0) {
267
+ width
268
+ } else {
269
+ null
270
+ }
271
+ val styleHeight = if (matchContentsVertical == true && height > 0) {
272
+ height
273
+ } else {
274
+ null
275
+ }
232
276
  shadowNodeProxy.setStyleSize(styleWidth?.toDouble(), styleHeight?.toDouble())
233
277
  }
234
278
 
@@ -263,8 +307,16 @@ internal class HostView(context: Context, appContext: AppContext) :
263
307
  val matchContentsVertical = props.matchContentsVertical.value
264
308
  val composeView = findComposeView()
265
309
  composeView.layoutParams = LayoutParams(
266
- if (matchContentsHorizontal == true) LayoutParams.WRAP_CONTENT else LayoutParams.MATCH_PARENT,
267
- if (matchContentsVertical == true) LayoutParams.WRAP_CONTENT else LayoutParams.MATCH_PARENT
310
+ if (matchContentsHorizontal == true) {
311
+ LayoutParams.WRAP_CONTENT
312
+ } else {
313
+ LayoutParams.MATCH_PARENT
314
+ },
315
+ if (matchContentsVertical == true) {
316
+ LayoutParams.WRAP_CONTENT
317
+ } else {
318
+ LayoutParams.MATCH_PARENT
319
+ }
268
320
  )
269
321
  }
270
322
 
@@ -176,7 +176,15 @@ internal fun LazyListScope.lazyRecycledItems(
176
176
  Box(
177
177
  modifier = Modifier.onSizeChanged { size ->
178
178
  if (content != null) {
179
- window.measure(itemKey, if (isVertical) size.height else size.width, revision)
179
+ window.measure(
180
+ itemKey,
181
+ if (isVertical) {
182
+ size.height
183
+ } else {
184
+ size.width
185
+ },
186
+ revision
187
+ )
180
188
  }
181
189
  }
182
190
  ) {
@@ -205,7 +213,11 @@ internal fun LazyListScope.lazyRecycledItems(
205
213
  */
206
214
  internal fun Modifier.lazyRecycledItemsCrossAxis(list: ViewGroup, isVertical: Boolean): Modifier =
207
215
  layout { measurable, constraints ->
208
- val crossAxisSize = if (isVertical) constraints.maxWidth else constraints.maxHeight
216
+ val crossAxisSize = if (isVertical) {
217
+ constraints.maxWidth
218
+ } else {
219
+ constraints.maxHeight
220
+ }
209
221
  for (index in 0..<list.childCount) {
210
222
  (list.getChildAt(index) as? LazyItemsView)?.window?.updateCrossAxisSize(crossAxisSize)
211
223
  }
@@ -145,7 +145,11 @@ fun FunctionalComposableScope.ModalBottomSheetContent(
145
145
  // then asked for light system bars, which turned the navigation bar white.
146
146
  val resolvedContentColor = props.contentColor.composeOrNull
147
147
  ?: MaterialTheme.colorScheme.contentColorFor(resolvedContainerColor).takeOrElse {
148
- if (resolvedContainerColor.luminance() > 0.5f) ComposeColor.Black else ComposeColor.White
148
+ if (resolvedContainerColor.luminance() > 0.5f) {
149
+ ComposeColor.Black
150
+ } else {
151
+ ComposeColor.White
152
+ }
149
153
  }
150
154
  val resolvedScrimColor = props.scrimColor.composeOrNull ?: BottomSheetDefaults.ScrimColor
151
155
  val dragHandleSlotView = findChildSlotView(view, "dragHandle")
@@ -21,6 +21,7 @@ import androidx.compose.foundation.border
21
21
  import androidx.compose.foundation.clickable
22
22
  import androidx.compose.foundation.combinedClickable
23
23
  import androidx.compose.foundation.horizontalScroll
24
+ import androidx.compose.foundation.layout.IntrinsicSize
24
25
  import androidx.compose.foundation.layout.defaultMinSize
25
26
  import androidx.compose.foundation.layout.fillMaxHeight
26
27
  import androidx.compose.foundation.layout.fillMaxSize
@@ -79,6 +80,7 @@ import expo.modules.kotlin.records.Field
79
80
  import expo.modules.kotlin.records.Record
80
81
  import expo.modules.kotlin.records.recordFromMap
81
82
  import expo.modules.kotlin.types.ConverterContext
83
+ import expo.modules.kotlin.types.Either
82
84
  import expo.modules.kotlin.types.Enumerable
83
85
  import expo.modules.kotlin.types.OptimizedRecord
84
86
  import expo.modules.kotlin.views.ComposableScope
@@ -133,6 +135,21 @@ data class WidthParams(
133
135
  @Field val width: Int = 0
134
136
  ) : Record
135
137
 
138
+ internal enum class IntrinsicSizeType(val value: String) : Enumerable {
139
+ MIN("min"),
140
+ MAX("max");
141
+
142
+ fun toComposeIntrinsicSize(): IntrinsicSize = when (this) {
143
+ MIN -> IntrinsicSize.Min
144
+ MAX -> IntrinsicSize.Max
145
+ }
146
+ }
147
+
148
+ @OptimizedRecord
149
+ internal data class ComposeWidthParams(
150
+ @Field val width: Either<Int, IntrinsicSizeType>? = null
151
+ ) : Record
152
+
136
153
  @OptimizedRecord
137
154
  data class HeightParams(
138
155
  @Field val height: Int = 0
@@ -168,7 +185,9 @@ data class BackgroundParams(
168
185
  // Color animation specs reuse the JS `$type` shape from `@expo/ui/jetpack-compose/modifiers/animation` (spring / tween / snap).
169
186
  // Keyframes are float-only and aren't supported for colors.
170
187
  private fun parseColorAnimationSpec(raw: Any?): AnimationSpec<androidx.compose.ui.graphics.Color>? {
171
- if (raw !is Map<*, *>) return null
188
+ if (raw !is Map<*, *>) {
189
+ return null
190
+ }
172
191
  return when (raw["\$type"]) {
173
192
  "spring" -> spring(
174
193
  dampingRatio = (raw["dampingRatio"] as? Number)?.toFloat() ?: Spring.DampingRatioNoBouncy,
@@ -409,7 +428,9 @@ object ModifierRegistry {
409
428
  scope: ComposableScope,
410
429
  eventDispatcher: ModifierEventDispatcher
411
430
  ): Modifier {
412
- if (modifiers.isNullOrEmpty()) return Modifier
431
+ if (modifiers.isNullOrEmpty()) {
432
+ return Modifier
433
+ }
413
434
  return modifiers.fold(Modifier as Modifier) { acc, config ->
414
435
  val type = config["\$type"]?.asString() ?: return@fold acc
415
436
  val modifier = modifierFactories[type]?.invoke(config, scope, appContext, eventDispatcher)
@@ -471,8 +492,12 @@ object ModifierRegistry {
471
492
  }
472
493
 
473
494
  register("width") { map, _, appContext, _ ->
474
- val params = recordFromMap<WidthParams>(map, appContext)
475
- Modifier.width(params.width.dp)
495
+ val width = recordFromMap<ComposeWidthParams>(map, appContext).width
496
+ if (width?.`is`(IntrinsicSizeType::class) == true) {
497
+ Modifier.width(width.second().toComposeIntrinsicSize())
498
+ } else {
499
+ Modifier.width((width?.first() ?: 0).dp)
500
+ }
476
501
  }
477
502
 
478
503
  register("height") { map, _, appContext, _ ->
@@ -498,7 +498,9 @@ private class TouchDispatchingRootViewGroup(
498
498
  // Use the (…, type, consumed) variant so we can read how much the sheet ate (consumed[1]).
499
499
  val consumed = IntArray(2)
500
500
  dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null, ViewCompat.TYPE_TOUCH, consumed)
501
- if (consumed[1] != 0) sheetMovingOnLastDragFrame = true
501
+ if (consumed[1] != 0) {
502
+ sheetMovingOnLastDragFrame = true
503
+ }
502
504
  }
503
505
 
504
506
  override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
@@ -179,7 +179,9 @@ fun pathFromShapeRecord(record: ShapeRecord, size: Size, density: Density): Path
179
179
  }
180
180
 
181
181
  fun shapeFromShapeRecord(shapeRecord: ShapeRecord?): Shape? {
182
- if (shapeRecord == null) return null
182
+ if (shapeRecord == null) {
183
+ return null
184
+ }
183
185
  return object : Shape {
184
186
  override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
185
187
  val path = pathFromShapeRecord(shapeRecord, size, density)
@@ -65,7 +65,9 @@ fun findChildSlotView(viewGroup: ViewGroup, slotName: String): SlotView? {
65
65
  inline fun <reified T> findChildOfType(viewGroup: ViewGroup): T? {
66
66
  for (index in 0..<viewGroup.size) {
67
67
  val child = viewGroup.getChildAt(index)
68
- if (child is T) return child
68
+ if (child is T) {
69
+ return child
70
+ }
69
71
  }
70
72
  return null
71
73
  }
@@ -83,7 +83,11 @@ fun FunctionalComposableScope.SnackbarHostContent(
83
83
  "long" -> SnackbarDuration.Long
84
84
  "indefinite" -> SnackbarDuration.Indefinite
85
85
  // M3 default: indefinite when there's an action label, else short.
86
- else -> if (options.actionLabel == null) SnackbarDuration.Short else SnackbarDuration.Indefinite
86
+ else -> if (options.actionLabel == null) {
87
+ SnackbarDuration.Short
88
+ } else {
89
+ SnackbarDuration.Indefinite
90
+ }
87
91
  }
88
92
  val result = try {
89
93
  withContext(scope.coroutineContext) {
@@ -134,7 +134,9 @@ enum class TextLineBreakType(val value: String) : Enumerable {
134
134
  }
135
135
 
136
136
  fun resolveFontFamily(name: String?, context: Context): FontFamily? {
137
- if (name == null) return null
137
+ if (name == null) {
138
+ return null
139
+ }
138
140
  return when (name) {
139
141
  "default" -> FontFamily.Default
140
142
  "sansSerif" -> FontFamily.SansSerif
@@ -32,7 +32,9 @@ val Color?.composeOrNull: androidx.compose.ui.graphics.Color?
32
32
  * Gets the ImageVector for a given icon name using reflection.
33
33
  */
34
34
  fun getImageVector(icon: String?): ImageVector? {
35
- if (icon.isNullOrEmpty()) return null
35
+ if (icon.isNullOrEmpty()) {
36
+ return null
37
+ }
36
38
  return try {
37
39
  val (theme, name) = icon.split(".")
38
40
  val clazz = Class.forName("androidx.compose.material.icons.$theme.${name}Kt")
@@ -38,7 +38,11 @@ internal fun Context.isSystemInDarkTheme(): Boolean {
38
38
  * Allows `expo-widgets` to back `getMaterialColors` inside the widgets JS runtime.
39
39
  */
40
40
  fun getMaterialColorTokens(context: Context, isDark: Boolean): Map<String, String> {
41
- val scheme = if (isDark) ExpoColorScheme.DARK else ExpoColorScheme.LIGHT
41
+ val scheme = if (isDark) {
42
+ ExpoColorScheme.DARK
43
+ } else {
44
+ ExpoColorScheme.LIGHT
45
+ }
42
46
  return scheme.toColorScheme(context).toTokenMap()
43
47
  }
44
48
 
@@ -87,7 +87,9 @@ internal data class KeyframesSpecParams(
87
87
 
88
88
  @Suppress("UNCHECKED_CAST")
89
89
  internal fun parseAnimationSpec(raw: Any?, converterContext: ConverterContext): AnimationSpec<Float>? {
90
- if (raw !is Map<*, *>) return null
90
+ if (raw !is Map<*, *>) {
91
+ return null
92
+ }
91
93
  val map = raw as Map<String, Any?>
92
94
  return when (raw["\$type"]) {
93
95
  "spring" -> recordFromMap<SpringSpecParams>(map, converterContext).toAnimationSpec()
@@ -199,7 +199,9 @@ class ImageLoader(
199
199
  * Detect if byte array contains XML content.
200
200
  */
201
201
  private fun isXmlContent(bytes: ByteArray): Boolean {
202
- if (bytes.size < 5) return false
202
+ if (bytes.size < 5) {
203
+ return false
204
+ }
203
205
 
204
206
  // Check for UTF-8 BOM
205
207
  var offset = 0
@@ -211,7 +213,9 @@ class ImageLoader(
211
213
  // Check if content starts with '<' (possibly with leading whitespace)
212
214
  for (i in offset until minOf(offset + 10, bytes.size)) {
213
215
  val b = bytes[i]
214
- if (b == '<'.code.toByte()) return true
216
+ if (b == '<'.code.toByte()) {
217
+ return true
218
+ }
215
219
  if (b != ' '.code.toByte() && b != '\t'.code.toByte() &&
216
220
  b != '\n'.code.toByte() && b != '\r'.code.toByte()
217
221
  ) {
@@ -83,7 +83,11 @@ class IconView(context: Context, appContext: AppContext) :
83
83
  // Render icon if painter available
84
84
  if (painter != null) {
85
85
  val resolvedTint = tint?.compose
86
- ?: if (inheritTint) LocalContentColor.current else androidx.compose.ui.graphics.Color.Unspecified
86
+ ?: if (inheritTint) {
87
+ LocalContentColor.current
88
+ } else {
89
+ androidx.compose.ui.graphics.Color.Unspecified
90
+ }
87
91
  Icon(
88
92
  painter = painter,
89
93
  contentDescription = contentDescription,
@@ -19,7 +19,9 @@ class ObservableState(initialValue: Any? = null) : SharedObject() {
19
19
  set(v) {
20
20
  _state.value = v
21
21
  // Skip re-invoking onChange if state.value was written from inside onChange.
22
- if (isNotifying) return
22
+ if (isNotifying) {
23
+ return
24
+ }
23
25
  isNotifying = true
24
26
  try {
25
27
  onChange?.invoke(v)
@@ -145,11 +145,19 @@ fun FunctionalComposableScope.BasicTextFieldContent(
145
145
  )
146
146
 
147
147
  val singleLine = props.singleLine
148
- val maxLines = props.maxLines ?: if (singleLine) 1 else Int.MAX_VALUE
148
+ val maxLines = props.maxLines ?: if (singleLine) {
149
+ 1
150
+ } else {
151
+ Int.MAX_VALUE
152
+ }
149
153
  val minLines = props.minLines ?: 1
150
154
 
151
155
  val textStyle = props.textStyle.toTextStyle(appContext.reactContext).let {
152
- if (it.color.isUnspecified) it.copy(color = MaterialTheme.colorScheme.onSurface) else it
156
+ if (it.color.isUnspecified) {
157
+ it.copy(color = MaterialTheme.colorScheme.onSurface)
158
+ } else {
159
+ it
160
+ }
153
161
  }
154
162
  val visualTransformation = props.visualTransformation.toVisualTransformation()
155
163
  val cursorBrush = SolidColor(props.cursorColor.composeOrNull ?: MaterialTheme.colorScheme.primary)
@@ -106,7 +106,11 @@ data class TextFieldSelectionColorsRecord(
106
106
 
107
107
  @Composable
108
108
  fun TextFieldColorsRecord.toColors(isOutlined: Boolean): TextFieldColors {
109
- val defaults = if (isOutlined) OutlinedTextFieldDefaults.colors() else TextFieldDefaults.colors()
109
+ val defaults = if (isOutlined) {
110
+ OutlinedTextFieldDefaults.colors()
111
+ } else {
112
+ TextFieldDefaults.colors()
113
+ }
110
114
  // Outlined and Filled TextField both use TextFieldDefault.colors
111
115
  return TextFieldDefaults.colors(
112
116
  focusedTextColor = focusedTextColor.composeOrNull ?: defaults.focusedTextColor,
@@ -229,14 +233,26 @@ fun FunctionalComposableScope.TextFieldContent(
229
233
 
230
234
  // Lines
231
235
  val singleLine = props.singleLine
232
- val maxLines = props.maxLines ?: if (singleLine) 1 else Int.MAX_VALUE
236
+ val maxLines = props.maxLines ?: if (singleLine) {
237
+ 1
238
+ } else {
239
+ Int.MAX_VALUE
240
+ }
233
241
  val minLines = props.minLines ?: 1
234
242
 
235
243
  val isOutlined = props.variant == TextFieldVariant.OUTLINED
236
244
  val shape = shapeFromShapeRecord(props.shape)
237
- ?: if (isOutlined) OutlinedTextFieldDefaults.shape else TextFieldDefaults.shape
245
+ ?: if (isOutlined) {
246
+ OutlinedTextFieldDefaults.shape
247
+ } else {
248
+ TextFieldDefaults.shape
249
+ }
238
250
  val baseColors = props.colors?.toColors(isOutlined)
239
- ?: if (isOutlined) OutlinedTextFieldDefaults.colors() else TextFieldDefaults.colors()
251
+ ?: if (isOutlined) {
252
+ OutlinedTextFieldDefaults.colors()
253
+ } else {
254
+ TextFieldDefaults.colors()
255
+ }
240
256
  val colors = props.textSelectionColors?.let { record ->
241
257
  val handle = record.handleColor.composeOrNull
242
258
  val background = record.backgroundColor.composeOrNull