@expo/ui 58.0.9 → 58.0.11

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 (84) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/HostView.kt +7 -1
  4. package/android/src/main/java/expo/modules/ui/RNHostView.kt +65 -16
  5. package/build/community/picker/Picker.android.js +7 -0
  6. package/build/community/picker/Picker.android.js.map +1 -1
  7. package/build/jetpack-compose/RNHostView/index.d.ts +6 -1
  8. package/build/jetpack-compose/RNHostView/index.js +9 -4
  9. package/build/jetpack-compose/RNHostView/index.js.map +1 -1
  10. package/build/swift-ui/RNHostView.d.ts +7 -2
  11. package/build/swift-ui/RNHostView.js +7 -3
  12. package/build/swift-ui/RNHostView.js.map +1 -1
  13. package/build/swift-ui/modifiers/containerBackground.d.ts +2 -2
  14. package/build/swift-ui/modifiers/containerBackground.js +2 -2
  15. package/build/swift-ui/modifiers/index.d.ts +9 -1
  16. package/build/swift-ui/modifiers/index.js +9 -0
  17. package/build/swift-ui/modifiers/index.js.map +1 -1
  18. package/build/universal/ListItem/ListItem.js +11 -2
  19. package/build/universal/ListItem/ListItem.js.map +1 -1
  20. package/build/universal/RNHostView/index.js +12 -5
  21. package/build/universal/RNHostView/index.js.map +1 -1
  22. package/build/universal/RNHostView/types.d.ts +9 -4
  23. package/build/universal/RNHostView/types.js.map +1 -1
  24. package/build/utils/matchContents.d.ts +10 -0
  25. package/build/utils/matchContents.js +16 -0
  26. package/build/utils/matchContents.js.map +1 -0
  27. package/ios/ExpoUIModule.swift +0 -1
  28. package/ios/Modifiers/ContainerBackgroundModifier.swift +23 -16
  29. package/ios/Modifiers/PreferredColorSchemeModifier.swift +12 -0
  30. package/ios/Modifiers/View+ModifierArray.swift +3 -3
  31. package/ios/Modifiers/ViewModifierRegistry.swift +11 -9
  32. package/ios/Modifiers/WidgetKitModifiers.swift +13 -0
  33. package/ios/RNHostView.swift +55 -9
  34. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.9/expo.modules.ui-58.0.9-sources.jar → 58.0.11/expo.modules.ui-58.0.11-sources.jar} +0 -0
  35. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11-sources.jar.md5 +1 -0
  36. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11-sources.jar.sha1 +1 -0
  37. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11-sources.jar.sha256 +1 -0
  38. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11-sources.jar.sha512 +1 -0
  39. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar +0 -0
  40. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar.md5 +1 -0
  41. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar.sha1 +1 -0
  42. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar.sha256 +1 -0
  43. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar.sha512 +1 -0
  44. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.9/expo.modules.ui-58.0.9.module → 58.0.11/expo.modules.ui-58.0.11.module} +22 -22
  45. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.module.md5 +1 -0
  46. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.module.sha1 +1 -0
  47. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.module.sha256 +1 -0
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.module.sha512 +1 -0
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.9/expo.modules.ui-58.0.9.pom → 58.0.11/expo.modules.ui-58.0.11.pom} +1 -1
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.pom.md5 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.pom.sha1 +1 -0
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.pom.sha256 +1 -0
  53. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.pom.sha512 +1 -0
  54. package/package.json +3 -3
  55. package/prebuilds/output/debug/xcframeworks/ExpoUI.tar.gz +0 -0
  56. package/prebuilds/output/release/xcframeworks/ExpoUI.tar.gz +0 -0
  57. package/src/community/picker/Picker.android.tsx +5 -0
  58. package/src/jetpack-compose/RNHostView/index.tsx +17 -6
  59. package/src/swift-ui/RNHostView.tsx +11 -4
  60. package/src/swift-ui/modifiers/containerBackground.ts +2 -2
  61. package/src/swift-ui/modifiers/index.ts +11 -0
  62. package/src/universal/ListItem/ListItem.tsx +10 -1
  63. package/src/universal/RNHostView/index.tsx +8 -3
  64. package/src/universal/RNHostView/types.ts +6 -4
  65. package/src/utils/matchContents.ts +14 -0
  66. package/ios/AccessoryWidgetBackgroundView.swift +0 -27
  67. package/ios/Modifiers/WidgetModifiers.swift +0 -70
  68. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.md5 +0 -1
  69. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha1 +0 -1
  70. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha256 +0 -1
  71. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha512 +0 -1
  72. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar +0 -0
  73. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.md5 +0 -1
  74. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha1 +0 -1
  75. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha256 +0 -1
  76. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha512 +0 -1
  77. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.md5 +0 -1
  78. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha1 +0 -1
  79. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha256 +0 -1
  80. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha512 +0 -1
  81. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.md5 +0 -1
  82. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha1 +0 -1
  83. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha256 +0 -1
  84. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha512 +0 -1
@@ -6,16 +6,21 @@ import type { UniversalBaseProps } from '../types';
6
6
  */
7
7
  export interface RNHostViewProps extends UniversalBaseProps {
8
8
  /**
9
- * When `true`, the host updates its size in the native view tree to match
10
- * the children's size. When `false`, the host uses the size of the parent
11
- * native view.
9
+ * When `true`, the host updates its size in the SwiftUI or Compose view tree to
10
+ * match the children's size. When `false`, the host uses the size of the parent
11
+ * SwiftUI or Compose view. Pass an object to choose per axis. For example,
12
+ * `{ vertical: true }` takes the width from the parent and the height from the
13
+ * children, so text wraps and grows vertically.
12
14
  *
13
15
  * Can only be set once on mount; changing it remounts the component.
14
16
  * @default false
15
17
  * @platform android
16
18
  * @platform ios
17
19
  */
18
- matchContents?: boolean;
20
+ matchContents?: boolean | {
21
+ vertical?: boolean;
22
+ horizontal?: boolean;
23
+ };
19
24
  onLayout?: (event: LayoutChangeEvent) => void;
20
25
  /**
21
26
  * The React Native view to host.
@@ -1 +1 @@
1
- {"version":3,"sources":["universal/RNHostView/types.ts"],"sourcesContent":[null],"names":[],"mappings":"AAKA;;CAEC,GACD,WAmBC"}
1
+ {"version":3,"sources":["universal/RNHostView/types.ts"],"sourcesContent":[null],"names":[],"mappings":"AAKA;;CAEC,GACD,WAqBC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Resolves `RNHostView`'s `matchContents` prop to one flag per axis.
3
+ */
4
+ export declare function resolveMatchContents(matchContents: boolean | {
5
+ vertical?: boolean;
6
+ horizontal?: boolean;
7
+ } | null | undefined): {
8
+ horizontal: boolean;
9
+ vertical: boolean;
10
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Resolves `RNHostView`'s `matchContents` prop to one flag per axis.
3
+ */ export function resolveMatchContents(matchContents) {
4
+ if (matchContents != null && typeof matchContents === 'object') {
5
+ return {
6
+ horizontal: matchContents.horizontal ?? false,
7
+ vertical: matchContents.vertical ?? false
8
+ };
9
+ }
10
+ return {
11
+ horizontal: matchContents ?? false,
12
+ vertical: matchContents ?? false
13
+ };
14
+ }
15
+
16
+ //# sourceMappingURL=matchContents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["utils/matchContents.ts"],"sourcesContent":[null],"names":["resolveMatchContents","matchContents","horizontal","vertical"],"mappings":"AAAA;;CAEC,GACD,OAAO,SAASA,qBACdC,aAAwF;IAExF,IAAIA,iBAAiB,QAAQ,OAAOA,kBAAkB,UAAU;QAC9D,OAAO;YACLC,YAAYD,cAAcC,UAAU,IAAI;YACxCC,UAAUF,cAAcE,QAAQ,IAAI;QACtC;IACF;IACA,OAAO;QAAED,YAAYD,iBAAiB;QAAOE,UAAUF,iBAAiB;IAAM;AAChF"}
@@ -204,7 +204,6 @@ public final class ExpoUIModule: Module {
204
204
  ExpoUIView(BackgroundView.self)
205
205
  ExpoUIView(MaskView.self)
206
206
  ExpoUIView(GridView.self)
207
- ExpoUIView(AccessoryWidgetBackgroundView.self)
208
207
  ExpoUIView(LinkView.self)
209
208
  ExpoUIView(TabView.self)
210
209
  ExpoUIView(Tab.self)
@@ -2,9 +2,6 @@
2
2
 
3
3
  import ExpoModulesCore
4
4
  import SwiftUI
5
- #if !os(tvOS)
6
- import WidgetKit
7
- #endif
8
5
 
9
6
  internal enum ContainerBackgroundPlacementOptions: String, Enumerable {
10
7
  case widget
@@ -12,10 +9,11 @@ internal enum ContainerBackgroundPlacementOptions: String, Enumerable {
12
9
  case navigationSplitView
13
10
 
14
11
  #if !os(tvOS) && !os(macOS)
12
+ // `widget` is declared in WidgetKit, so expo-widgets applies it through `ViewModifierRegistry.widgetKit`.
15
13
  @available(iOS 18.0, *)
16
- var toContainerBackgroundPlacement: ContainerBackgroundPlacement {
14
+ var toContainerBackgroundPlacement: ContainerBackgroundPlacement? {
17
15
  switch self {
18
- case .widget: return .widget
16
+ case .widget: return nil
19
17
  case .navigation: return .navigation
20
18
  case .navigationSplitView: return .navigationSplitView
21
19
  }
@@ -28,20 +26,17 @@ internal struct ContainerBackgroundModifier: ViewModifier, Record {
28
26
  @Field var container: ContainerBackgroundPlacementOptions?
29
27
 
30
28
  func body(content: Content) -> some View {
31
- #if os(tvOS)
29
+ #if os(tvOS) || os(macOS)
32
30
  content
33
- #elseif os(macOS)
34
- if let shapeStyle = style?.toAnyShapeStyle(), container == .widget {
35
- content.containerBackground(shapeStyle, for: .widget)
36
- } else {
37
- content
38
- }
39
31
  #else
40
32
  if let shapeStyle = style?.toAnyShapeStyle(), let container {
41
- if #available(iOS 18.0, *) {
42
- content.containerBackground(shapeStyle, for: container.toContainerBackgroundPlacement)
43
- } else if #available(iOS 17.0, *) {
44
- content.containerBackground(shapeStyle, for: .widget)
33
+ if container == .widget, let widgetKit = ViewModifierRegistry.widgetKit {
34
+ widgetKit.containerBackground(AnyView(content), style: shapeStyle)
35
+ } else if #available(iOS 18.0, *), let placement = container.toContainerBackgroundPlacement {
36
+ content.containerBackground(shapeStyle, for: placement)
37
+ } else if let widgetKit = ViewModifierRegistry.widgetKit {
38
+ // On iOS 17, the other placements fall back to `widget`.
39
+ widgetKit.containerBackground(AnyView(content), style: shapeStyle)
45
40
  } else {
46
41
  content
47
42
  }
@@ -50,4 +45,16 @@ internal struct ContainerBackgroundModifier: ViewModifier, Record {
50
45
  }
51
46
  #endif
52
47
  }
48
+
49
+ #if DEBUG
50
+ private static var didWarnAboutWidgetPlacement = false
51
+
52
+ func warnIfWidgetPlacementIsUnavailable() {
53
+ guard container == .widget, ViewModifierRegistry.widgetKit == nil, !Self.didWarnAboutWidgetPlacement else {
54
+ return
55
+ }
56
+ Self.didWarnAboutWidgetPlacement = true
57
+ log.warn("containerBackground with the 'widget' placement has no effect here, because it only applies inside widgets rendered by expo-widgets. Use the 'navigation' or 'navigationSplitView' placement in app screens.")
58
+ }
59
+ #endif
53
60
  }
@@ -0,0 +1,12 @@
1
+ // Copyright 2025-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+ import SwiftUI
5
+
6
+ internal struct PreferredColorSchemeModifier: ViewModifier, Record {
7
+ @Field var colorScheme: ColorSchemeType?
8
+
9
+ func body(content: Content) -> some View {
10
+ content.preferredColorScheme(colorScheme?.toNativeColorScheme())
11
+ }
12
+ }
@@ -67,10 +67,10 @@ internal extension Image {
67
67
  )
68
68
  }
69
69
 
70
- if #available(iOS 18.0, macOS 15.0, *),
70
+ if let widgetKit = ViewModifierRegistry.widgetKit,
71
71
  let modifierConfig = modifiers.first(where: { $0["$type"] as? String == "widgetAccentedRenderingMode" }),
72
- let modifier = try? WidgetAccentedRenderingModeModifier(from: modifierConfig, appContext: appContext) {
73
- modifier.apply(to: image)
72
+ let view = widgetKit.widgetAccentedRenderingMode(image, params: modifierConfig, appContext: appContext) {
73
+ view
74
74
  } else {
75
75
  image
76
76
  }
@@ -1533,6 +1533,8 @@ public class ViewModifierRegistry {
1533
1533
  public typealias ModifierFactory = ([String: Any], AppContext, EventDispatcher) throws -> any ViewModifier
1534
1534
  private(set) internal var modifierFactories: [String: ModifierFactory] = [:]
1535
1535
 
1536
+ public static var widgetKit: WidgetKitModifiers?
1537
+
1536
1538
  private init() {
1537
1539
  registerBuiltInModifiers()
1538
1540
  }
@@ -2309,6 +2311,10 @@ extension ViewModifierRegistry {
2309
2311
  return try ScrollDisabledModifier(from: params, appContext: appContext)
2310
2312
  }
2311
2313
 
2314
+ register("preferredColorScheme") { params, appContext, _ in
2315
+ return try PreferredColorSchemeModifier(from: params, appContext: appContext)
2316
+ }
2317
+
2312
2318
  register("scrollClipDisabled") { params, appContext, _ in
2313
2319
  return try ScrollClipDisabledModifier(from: params, appContext: appContext)
2314
2320
  }
@@ -2393,14 +2399,6 @@ extension ViewModifierRegistry {
2393
2399
  return try ContentTransitionModifier(from: params, appContext: appContext)
2394
2400
  }
2395
2401
 
2396
- register("widgetURL") { params, appContext, _ in
2397
- return try WidgetURLModifier(from: params, appContext: appContext)
2398
- }
2399
-
2400
- register("activityBackgroundTint") { params, appContext, _ in
2401
- return try ActivityBackgroundTintModifier(from: params, appContext: appContext)
2402
- }
2403
-
2404
2402
  register("keyboardType") { params, appContext, _ in
2405
2403
  return try KeyboardTypeModifier(from: params, appContext: appContext)
2406
2404
  }
@@ -2414,7 +2412,11 @@ extension ViewModifierRegistry {
2414
2412
  }
2415
2413
 
2416
2414
  register("containerBackground") { params, appContext, _ in
2417
- return try ContainerBackgroundModifier(from: params, appContext: appContext)
2415
+ let modifier = try ContainerBackgroundModifier(from: params, appContext: appContext)
2416
+ #if DEBUG
2417
+ modifier.warnIfWidgetPlacementIsUnavailable()
2418
+ #endif
2419
+ return modifier
2418
2420
  }
2419
2421
 
2420
2422
  register("symbolEffect") { params, appContext, _ in
@@ -0,0 +1,13 @@
1
+ // Copyright 2026-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+ import SwiftUI
5
+
6
+ /**
7
+ * The parts of SwiftUI that are declared in WidgetKit. expo-widgets sets
8
+ * `ViewModifierRegistry.widgetKit`, so ExpoUI does not link WidgetKit.
9
+ */
10
+ public protocol WidgetKitModifiers {
11
+ func containerBackground(_ view: AnyView, style: AnyShapeStyle) -> AnyView
12
+ func widgetAccentedRenderingMode(_ image: Image, params: [String: Any], appContext: AppContext) -> AnyView?
13
+ }
@@ -4,7 +4,8 @@ import SwiftUI
4
4
  import ExpoModulesCore
5
5
 
6
6
  internal final class RNHostViewProps: ExpoSwiftUI.ViewProps {
7
- @Field var matchContents: Bool = false
7
+ @Field var matchContentsHorizontal: Bool = false
8
+ @Field var matchContentsVertical: Bool = false
8
9
  /**
9
10
  Adds LeafNode and MeasurableYogaNode trait in Shadow node
10
11
  */
@@ -50,8 +51,13 @@ struct RNHostView: ExpoSwiftUI.View {
50
51
 
51
52
  @ViewBuilder
52
53
  private var hostedContent: some View {
53
- if props.matchContents, let childUIView = firstChildUIView {
54
- ApplySizeFromYogaNode(childUIView: childUIView) {
54
+ if matchesContents, let childUIView = firstChildUIView {
55
+ ApplySizeFromYogaNode(
56
+ childUIView: childUIView,
57
+ horizontal: props.matchContentsHorizontal,
58
+ vertical: props.matchContentsVertical,
59
+ shadowNodeProxy: props.shadowNodeProxy
60
+ ) {
55
61
  Children()
56
62
  }
57
63
  .onAppear {
@@ -62,7 +68,7 @@ struct RNHostView: ExpoSwiftUI.View {
62
68
  .onDisappear {
63
69
  touchHandler.detach()
64
70
  }
65
- } else if props.matchContents {
71
+ } else if matchesContents {
66
72
  // No hosted UIView (a pure SwiftUI child, e.g. Text/Image). Render it at its
67
73
  // natural size instead of falling into the fill branch below, which would
68
74
  // stretch a self-sizing SwiftUI view to fill its container.
@@ -87,6 +93,10 @@ struct RNHostView: ExpoSwiftUI.View {
87
93
  }
88
94
  }
89
95
 
96
+ private var matchesContents: Bool {
97
+ props.matchContentsHorizontal || props.matchContentsVertical
98
+ }
99
+
90
100
  private var firstChildUIView: UIView? {
91
101
  props.children?.first?.uiView
92
102
  }
@@ -143,20 +153,52 @@ private final class RNHostTouchHandler: ObservableObject {
143
153
  }
144
154
  }
145
155
 
146
- // Sets SwiftUI view size from Yoga node size
156
+ // Sets SwiftUI view size from Yoga node size on the matched axes
147
157
  // Listens to Yoga node size changes and updates the SwiftUI view size
158
+ // An axis that is not matched fills the parent and reports its size to the Yoga node instead
148
159
  private struct ApplySizeFromYogaNode<Content: SwiftUI.View>: SwiftUI.View {
149
160
  @StateObject private var observer: Observer
161
+ let horizontal: Bool
162
+ let vertical: Bool
163
+ let shadowNodeProxy: ExpoSwiftUI.ShadowNodeProxy
150
164
  let content: Content
151
165
 
152
- init(childUIView: UIView, @ViewBuilder content: () -> Content) {
166
+ init(
167
+ childUIView: UIView,
168
+ horizontal: Bool,
169
+ vertical: Bool,
170
+ shadowNodeProxy: ExpoSwiftUI.ShadowNodeProxy,
171
+ @ViewBuilder content: () -> Content
172
+ ) {
153
173
  _observer = StateObject(wrappedValue: Observer(view: childUIView))
174
+ self.horizontal = horizontal
175
+ self.vertical = vertical
176
+ self.shadowNodeProxy = shadowNodeProxy
154
177
  self.content = content()
155
178
  }
156
179
 
157
180
  var body: some SwiftUI.View {
158
- content
159
- .frame(width: observer.size.width, height: observer.size.height)
181
+ if horizontal && vertical {
182
+ content
183
+ .frame(width: observer.size.width, height: observer.size.height)
184
+ } else {
185
+ content
186
+ .frame(
187
+ width: horizontal ? observer.size.width : nil,
188
+ height: vertical ? observer.size.height : nil
189
+ )
190
+ .frame(
191
+ maxWidth: horizontal ? nil : .infinity,
192
+ maxHeight: vertical ? nil : .infinity
193
+ )
194
+ .modifier(
195
+ ReportSizeToYogaNodeModifier(
196
+ shadowNodeProxy: shadowNodeProxy,
197
+ reportWidth: !horizontal,
198
+ reportHeight: !vertical
199
+ )
200
+ )
201
+ }
160
202
  }
161
203
 
162
204
  @MainActor
@@ -183,9 +225,13 @@ private struct ApplySizeFromYogaNode<Content: SwiftUI.View>: SwiftUI.View {
183
225
  // Listens to SwiftUI view size changes and updates the Yoga node size
184
226
  private struct ReportSizeToYogaNodeModifier: ViewModifier {
185
227
  let shadowNodeProxy: ExpoSwiftUI.ShadowNodeProxy
228
+ var reportWidth = true
229
+ var reportHeight = true
186
230
 
187
231
  private func handleSizeChange(_ size: CGSize) {
188
- shadowNodeProxy.setViewSize?(size)
232
+ shadowNodeProxy.setViewSize?(
233
+ CGSize(width: reportWidth ? size.width : .nan, height: reportHeight ? size.height : .nan)
234
+ )
189
235
  }
190
236
 
191
237
  func body(content: Content) -> some View {
@@ -0,0 +1 @@
1
+ d6b5917f7e254bed3b859860b39f0cf57b943148a0dc5c25282599caaa5bbf7e
@@ -0,0 +1 @@
1
+ 7325da1dbb0f220f807982fa7797678dba275209f74efde81b39d4ecf3452573708a111629552ae98257631d5c8e9d26438d10a50172c6d731e247d20f8762c0
@@ -0,0 +1 @@
1
+ 552a8fdfc1afb51afb7bf9f742f2917988ccb39d
@@ -0,0 +1 @@
1
+ 3c1582041a0a49f0df088ad60c5ee3c2333da74afff9a783f4e31984ef5f975d
@@ -0,0 +1 @@
1
+ 453c085a9a3f87728a04202f8345587720468598c7873813e572b87013ff025c384008e4c77d5ca54db253df56b5545b6180aec60b0164afce10cb1ad8c128cc
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "expo.modules.ui",
5
5
  "module": "expo.modules.ui",
6
- "version": "58.0.9",
6
+ "version": "58.0.11",
7
7
  "attributes": {
8
8
  "org.gradle.status": "release"
9
9
  }
@@ -24,13 +24,13 @@
24
24
  },
25
25
  "files": [
26
26
  {
27
- "name": "expo.modules.ui-58.0.9.aar",
28
- "url": "expo.modules.ui-58.0.9.aar",
29
- "size": 1842529,
30
- "sha512": "1c0e1676d8ed6f47450bb5e7f28d486d275a7e0264893ea78bac3cacc0341aa3e0097f5c033fb601eac07fc8482498005a51f27b8bffcc7249366b34b14b40f5",
31
- "sha256": "a88a20a3df6e5cfd20d54e45c597425a5e052a5b8ba95a41d6b5a92aa8c02fc6",
32
- "sha1": "518280855fc0ebe67334a36edceffbfbce55f947",
33
- "md5": "03491dfb69ff8c25616d5f8ca35be94a"
27
+ "name": "expo.modules.ui-58.0.11.aar",
28
+ "url": "expo.modules.ui-58.0.11.aar",
29
+ "size": 1843657,
30
+ "sha512": "453c085a9a3f87728a04202f8345587720468598c7873813e572b87013ff025c384008e4c77d5ca54db253df56b5545b6180aec60b0164afce10cb1ad8c128cc",
31
+ "sha256": "3c1582041a0a49f0df088ad60c5ee3c2333da74afff9a783f4e31984ef5f975d",
32
+ "sha1": "552a8fdfc1afb51afb7bf9f742f2917988ccb39d",
33
+ "md5": "42294a6398d445ac12b85609173d6710"
34
34
  }
35
35
  ]
36
36
  },
@@ -141,13 +141,13 @@
141
141
  ],
142
142
  "files": [
143
143
  {
144
- "name": "expo.modules.ui-58.0.9.aar",
145
- "url": "expo.modules.ui-58.0.9.aar",
146
- "size": 1842529,
147
- "sha512": "1c0e1676d8ed6f47450bb5e7f28d486d275a7e0264893ea78bac3cacc0341aa3e0097f5c033fb601eac07fc8482498005a51f27b8bffcc7249366b34b14b40f5",
148
- "sha256": "a88a20a3df6e5cfd20d54e45c597425a5e052a5b8ba95a41d6b5a92aa8c02fc6",
149
- "sha1": "518280855fc0ebe67334a36edceffbfbce55f947",
150
- "md5": "03491dfb69ff8c25616d5f8ca35be94a"
144
+ "name": "expo.modules.ui-58.0.11.aar",
145
+ "url": "expo.modules.ui-58.0.11.aar",
146
+ "size": 1843657,
147
+ "sha512": "453c085a9a3f87728a04202f8345587720468598c7873813e572b87013ff025c384008e4c77d5ca54db253df56b5545b6180aec60b0164afce10cb1ad8c128cc",
148
+ "sha256": "3c1582041a0a49f0df088ad60c5ee3c2333da74afff9a783f4e31984ef5f975d",
149
+ "sha1": "552a8fdfc1afb51afb7bf9f742f2917988ccb39d",
150
+ "md5": "42294a6398d445ac12b85609173d6710"
151
151
  }
152
152
  ]
153
153
  },
@@ -161,13 +161,13 @@
161
161
  },
162
162
  "files": [
163
163
  {
164
- "name": "expo.modules.ui-58.0.9-sources.jar",
165
- "url": "expo.modules.ui-58.0.9-sources.jar",
166
- "size": 110135,
167
- "sha512": "d1b747e78264dad3ee7a5322811ff5d079433fa34a32ebb5ae5c29c5c3ef412746a8c10d3e22937037b45a4b909783329deebf92b09e5c1ef486807a5978ffc6",
168
- "sha256": "73965c56280c334bb29231b9523362401285d6609ef8b75839f1c89b6a3aa4f7",
169
- "sha1": "a5da15def1d399f452a19c62651e73a942d873ec",
170
- "md5": "ec47224b2d335b3f472a55d70f343b8f"
164
+ "name": "expo.modules.ui-58.0.11-sources.jar",
165
+ "url": "expo.modules.ui-58.0.11-sources.jar",
166
+ "size": 110713,
167
+ "sha512": "7325da1dbb0f220f807982fa7797678dba275209f74efde81b39d4ecf3452573708a111629552ae98257631d5c8e9d26438d10a50172c6d731e247d20f8762c0",
168
+ "sha256": "d6b5917f7e254bed3b859860b39f0cf57b943148a0dc5c25282599caaa5bbf7e",
169
+ "sha1": "35f9c28864e4c66ebf31d87331aaf606420295dd",
170
+ "md5": "1302e48111e4d1b9df2e41d53b5aced4"
171
171
  }
172
172
  ]
173
173
  }
@@ -0,0 +1 @@
1
+ 177d63d30567acf8813edf88c6a61165ae8327d9
@@ -0,0 +1 @@
1
+ 8c9b268c255ce001213ec694e09cb488a61af94350f20dfa4553b6e65c21574c
@@ -0,0 +1 @@
1
+ b782bd23e94df6526eeb28aa8c94a5c719d2ffcb329810adf7d76424071de7f4d817203ac96adc5ccfe50665a0551860756aec9484a769e4f5b03b4f9d3bfb7d
@@ -9,7 +9,7 @@
9
9
  <modelVersion>4.0.0</modelVersion>
10
10
  <groupId>expo.modules.ui</groupId>
11
11
  <artifactId>expo.modules.ui</artifactId>
12
- <version>58.0.9</version>
12
+ <version>58.0.11</version>
13
13
  <packaging>aar</packaging>
14
14
  <name>expo.modules.ui</name>
15
15
  <url>https://github.com/expo/expo</url>
@@ -0,0 +1 @@
1
+ 74675a495c2af28ac07bb6a9bff5900800df5f1b
@@ -0,0 +1 @@
1
+ 87480436c37f4080a36ee31a7192215c066e69d8df32f237ce1c2d172b84d9c8
@@ -0,0 +1 @@
1
+ e78b6109060d7761704f0472a04d1ee83bc40d9e31136840bbb8b79888f16c8084d5cda64a9ccb89cb490eceb21c7154e9df30873c4004958203917d0da0a037
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/ui",
3
- "version": "58.0.9",
3
+ "version": "58.0.11",
4
4
  "description": "A collection of UI components",
5
5
  "keywords": [
6
6
  "Jetpack Compose",
@@ -143,12 +143,12 @@
143
143
  "@babel/core": "^7.26.0",
144
144
  "@playwright/test": "^1.59.0",
145
145
  "@testing-library/react": "^16.3.0",
146
- "@testing-library/react-native": "^13.3.0",
146
+ "@testing-library/react-native": "^14.0.1",
147
147
  "@types/babel__core": "^7.20.5",
148
148
  "@types/jest": "^29.2.1",
149
149
  "@types/node": "^22.14.0",
150
150
  "@types/react": "~19.3.0",
151
- "expo-module-scripts": "56.0.4",
151
+ "expo-module-scripts": "56.0.5",
152
152
  "react-native-reanimated": "4.7.0",
153
153
  "react-native-worklets": "0.13.0"
154
154
  },
@@ -36,6 +36,11 @@ export function Picker<T extends PickerItemValue>(props: PickerProps<T>) {
36
36
  const selectedLabel = selectedItem?.label ?? '';
37
37
  const labelState = useNativeState(selectedLabel);
38
38
 
39
+ // `useNativeState` only captures its initial value, so push later changes to the field.
40
+ React.useEffect(() => {
41
+ labelState.set(selectedLabel);
42
+ }, [labelState, selectedLabel]);
43
+
39
44
  return (
40
45
  <Host style={style} matchContents={{ vertical: true }}>
41
46
  <ExposedDropdownMenuBox
@@ -4,6 +4,7 @@ import type { LayoutChangeEvent } from 'react-native';
4
4
 
5
5
  import { PresentedContentContext, useIsPresentedInOwnWindow } from '../../PresentedContentContext';
6
6
  import type { ModifierConfig } from '../../types';
7
+ import { resolveMatchContents } from '../../utils/matchContents';
7
8
  import type { PrimitiveBaseProps } from '../layout';
8
9
  import { createViewModifierEventListener } from '../modifiers/utils';
9
10
 
@@ -11,10 +12,12 @@ export interface RNHostProps extends PrimitiveBaseProps {
11
12
  /**
12
13
  * When `true`, the RNHost will update its size in the Jetpack Compose view tree to match the children's size.
13
14
  * When `false`, the RNHost will use the size of the parent Jetpack Compose View.
15
+ * Pass an object to choose per axis. For example, `{ vertical: true }` takes the width from the
16
+ * parent and the height from the children, so text wraps and grows vertically.
14
17
  * Can be only set once on mount.
15
18
  * @default false
16
19
  */
17
- matchContents?: boolean;
20
+ matchContents?: boolean | { vertical?: boolean; horizontal?: boolean };
18
21
  /**
19
22
  * Called on mount and whenever this view's layout in the React Native view tree changes.
20
23
  * With `matchContents`, the reported size is the one measured from the hosted view.
@@ -30,8 +33,10 @@ export interface RNHostProps extends PrimitiveBaseProps {
30
33
  modifiers?: ModifierConfig[];
31
34
  }
32
35
 
33
- type NativeRNHostProps = RNHostProps & {
36
+ type NativeRNHostProps = Omit<RNHostProps, 'matchContents'> & {
34
37
  layoutRoot: boolean;
38
+ matchContentsHorizontal: boolean;
39
+ matchContentsVertical: boolean;
35
40
  /**
36
41
  * Internal. Drives the shadow node's content measurement, see
37
42
  * `ExpoViewShadowNode::sizesToContent`.
@@ -44,13 +49,17 @@ const NativeRNHostView: ComponentType<NativeRNHostProps> = requireNativeView(
44
49
  );
45
50
 
46
51
  function transformProps(props: RNHostProps, layoutRoot: boolean): NativeRNHostProps {
47
- const { modifiers, ...restProps } = props;
52
+ const { modifiers, matchContents, ...restProps } = props;
53
+ const { horizontal: matchContentsHorizontal, vertical: matchContentsVertical } =
54
+ resolveMatchContents(matchContents);
48
55
  return {
49
56
  modifiers,
50
57
  ...(modifiers ? createViewModifierEventListener(modifiers) : undefined),
51
58
  ...restProps,
52
59
  layoutRoot,
53
- expoInternalSizeFromChildren: props.matchContents,
60
+ matchContentsHorizontal,
61
+ matchContentsVertical,
62
+ expoInternalSizeFromChildren: matchContentsHorizontal || matchContentsVertical,
54
63
  };
55
64
  }
56
65
 
@@ -61,12 +70,14 @@ export function RNHostView(props: RNHostProps) {
61
70
  // is what makes a `Pressable` drop its press on the first finger movement.
62
71
  const layoutRoot = useIsPresentedInOwnWindow();
63
72
 
73
+ const nativeProps = transformProps(props, layoutRoot);
74
+
64
75
  return (
65
76
  <NativeRNHostView
66
- {...transformProps(props, layoutRoot)}
77
+ {...nativeProps}
67
78
  // `matchContents` can only be used once on mount
68
79
  // So we force unmount when it changes to prevent unexpected layout
69
- key={props.matchContents ? 'matchContents' : 'noMatchContents'}>
80
+ key={`${nativeProps.matchContentsHorizontal}-${nativeProps.matchContentsVertical}`}>
70
81
  {/* Reset context here so only nearest RNHostView becomes the layout root for its children, and not any other RNHostView above it in the tree. */}
71
82
  <PresentedContentContext.Provider value={false}>
72
83
  {props.children}