@expo/ui 57.0.12 → 57.0.14

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 (130) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +17 -3
  4. package/android/src/main/java/expo/modules/ui/ModalBottomSheetView.kt +50 -0
  5. package/android/src/main/java/expo/modules/ui/ProgressView.kt +31 -0
  6. package/android/src/main/java/expo/modules/ui/RNHostView.kt +141 -11
  7. package/build/PresentedContentContext.d.ts +18 -0
  8. package/build/PresentedContentContext.d.ts.map +1 -0
  9. package/build/community/pager-view/PagerView.android.d.ts.map +1 -1
  10. package/build/jetpack-compose/AlertDialog/index.d.ts.map +1 -1
  11. package/build/jetpack-compose/BasicAlertDialog/index.d.ts.map +1 -1
  12. package/build/jetpack-compose/DropdownMenu/index.d.ts.map +1 -1
  13. package/build/jetpack-compose/ExposedDropdownMenuBox/ExposedDropdownMenu.d.ts.map +1 -1
  14. package/build/jetpack-compose/Host/index.d.ts +3 -0
  15. package/build/jetpack-compose/Host/index.d.ts.map +1 -1
  16. package/build/jetpack-compose/ModalBottomSheet/index.d.ts.map +1 -1
  17. package/build/jetpack-compose/Progress/index.d.ts +25 -2
  18. package/build/jetpack-compose/Progress/index.d.ts.map +1 -1
  19. package/build/jetpack-compose/RNHostView/index.d.ts +0 -6
  20. package/build/jetpack-compose/RNHostView/index.d.ts.map +1 -1
  21. package/build/jetpack-compose/TextField/shared.d.ts +2 -1
  22. package/build/jetpack-compose/TextField/shared.d.ts.map +1 -1
  23. package/build/jetpack-compose/Tooltip/index.d.ts.map +1 -1
  24. package/build/keyboard/index.d.ts +43 -0
  25. package/build/keyboard/index.d.ts.map +1 -0
  26. package/build/keyboard/interop.d.ts +16 -0
  27. package/build/keyboard/interop.d.ts.map +1 -0
  28. package/build/keyboard/textInputState.d.ts +2 -0
  29. package/build/keyboard/textInputState.d.ts.map +1 -0
  30. package/build/keyboard/textInputState.web.d.ts +11 -0
  31. package/build/keyboard/textInputState.web.d.ts.map +1 -0
  32. package/build/swift-ui/Background/index.d.ts +18 -0
  33. package/build/swift-ui/Background/index.d.ts.map +1 -0
  34. package/build/swift-ui/BottomSheet/index.d.ts.map +1 -1
  35. package/build/swift-ui/Host/index.d.ts +3 -0
  36. package/build/swift-ui/Host/index.d.ts.map +1 -1
  37. package/build/swift-ui/Popover/index.d.ts.map +1 -1
  38. package/build/swift-ui/RNHostView.d.ts +2 -1
  39. package/build/swift-ui/RNHostView.d.ts.map +1 -1
  40. package/build/swift-ui/SecureField/index.d.ts.map +1 -1
  41. package/build/swift-ui/TextField/index.d.ts.map +1 -1
  42. package/build/swift-ui/index.d.ts +1 -0
  43. package/build/swift-ui/index.d.ts.map +1 -1
  44. package/build/swift-ui/modifiers/index.d.ts +21 -1
  45. package/build/swift-ui/modifiers/index.d.ts.map +1 -1
  46. package/build/universal/BottomSheet/index.android.d.ts +1 -1
  47. package/build/universal/BottomSheet/index.android.d.ts.map +1 -1
  48. package/build/universal/BottomSheet/types.d.ts +14 -0
  49. package/build/universal/BottomSheet/types.d.ts.map +1 -1
  50. package/build/utils/useMergeRefs.d.ts +12 -0
  51. package/build/utils/useMergeRefs.d.ts.map +1 -0
  52. package/expo-module.config.json +1 -1
  53. package/ios/BackgroundView.swift +34 -0
  54. package/ios/ColorPickerView.swift +1 -1
  55. package/ios/ExpoUIModule.swift +4 -0
  56. package/ios/HostView.swift +7 -0
  57. package/ios/Modifiers/ViewModifierRegistry.swift +48 -0
  58. package/ios/RNHostView.swift +65 -4
  59. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{57.0.12/expo.modules.ui-57.0.12-sources.jar → 57.0.14/expo.modules.ui-57.0.14-sources.jar} +0 -0
  60. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14-sources.jar.md5 +1 -0
  61. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14-sources.jar.sha1 +1 -0
  62. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14-sources.jar.sha256 +1 -0
  63. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14-sources.jar.sha512 +1 -0
  64. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.aar +0 -0
  65. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.aar.md5 +1 -0
  66. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.aar.sha1 +1 -0
  67. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.aar.sha256 +1 -0
  68. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.aar.sha512 +1 -0
  69. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{57.0.12/expo.modules.ui-57.0.12.module → 57.0.14/expo.modules.ui-57.0.14.module} +22 -22
  70. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.module.md5 +1 -0
  71. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.module.sha1 +1 -0
  72. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.module.sha256 +1 -0
  73. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.module.sha512 +1 -0
  74. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{57.0.12/expo.modules.ui-57.0.12.pom → 57.0.14/expo.modules.ui-57.0.14.pom} +1 -1
  75. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.pom.md5 +1 -0
  76. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.pom.sha1 +1 -0
  77. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.pom.sha256 +1 -0
  78. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.14/expo.modules.ui-57.0.14.pom.sha512 +1 -0
  79. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
  80. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
  81. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
  82. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
  83. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
  84. package/package.json +4 -4
  85. package/src/PresentedContentContext.tsx +22 -0
  86. package/src/community/pager-view/PagerView.android.tsx +1 -7
  87. package/src/jetpack-compose/AlertDialog/index.tsx +6 -1
  88. package/src/jetpack-compose/BasicAlertDialog/index.tsx +7 -1
  89. package/src/jetpack-compose/DropdownMenu/index.tsx +7 -1
  90. package/src/jetpack-compose/ExposedDropdownMenuBox/ExposedDropdownMenu.tsx +3 -1
  91. package/src/jetpack-compose/Host/index.tsx +28 -17
  92. package/src/jetpack-compose/ModalBottomSheet/index.tsx +8 -1
  93. package/src/jetpack-compose/Progress/index.tsx +32 -2
  94. package/src/jetpack-compose/RNHostView/index.tsx +16 -13
  95. package/src/jetpack-compose/TextField/shared.ts +7 -1
  96. package/src/jetpack-compose/Tooltip/index.tsx +2 -1
  97. package/src/keyboard/index.tsx +243 -0
  98. package/src/keyboard/interop.ts +99 -0
  99. package/src/keyboard/textInputState.ts +2 -0
  100. package/src/keyboard/textInputState.web.ts +16 -0
  101. package/src/swift-ui/Background/index.tsx +38 -0
  102. package/src/swift-ui/BottomSheet/index.tsx +4 -1
  103. package/src/swift-ui/Host/index.tsx +33 -18
  104. package/src/swift-ui/Popover/index.tsx +7 -1
  105. package/src/swift-ui/RNHostView.tsx +17 -3
  106. package/src/swift-ui/SecureField/index.tsx +8 -2
  107. package/src/swift-ui/TextField/index.tsx +8 -1
  108. package/src/swift-ui/index.tsx +1 -0
  109. package/src/swift-ui/modifiers/index.ts +25 -0
  110. package/src/ts-declarations/react-native-text-input-state.d.ts +26 -0
  111. package/src/universal/BottomSheet/index.android.tsx +4 -1
  112. package/src/universal/BottomSheet/types.ts +17 -0
  113. package/src/utils/useMergeRefs.ts +47 -0
  114. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12-sources.jar.md5 +0 -1
  115. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12-sources.jar.sha1 +0 -1
  116. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12-sources.jar.sha256 +0 -1
  117. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12-sources.jar.sha512 +0 -1
  118. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.aar +0 -0
  119. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.aar.md5 +0 -1
  120. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.aar.sha1 +0 -1
  121. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.aar.sha256 +0 -1
  122. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.aar.sha512 +0 -1
  123. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.module.md5 +0 -1
  124. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.module.sha1 +0 -1
  125. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.module.sha256 +0 -1
  126. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.module.sha512 +0 -1
  127. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.pom.md5 +0 -1
  128. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.pom.sha1 +0 -1
  129. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.pom.sha256 +0 -1
  130. package/local-maven-repo/expo/modules/ui/expo.modules.ui/57.0.12/expo.modules.ui-57.0.12.pom.sha512 +0 -1
@@ -0,0 +1,34 @@
1
+ // Copyright 2025-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+ import SwiftUI
5
+
6
+ internal class BackgroundViewProps: UIBaseViewProps {
7
+ @Field var alignment: AlignmentOptions?
8
+ }
9
+
10
+ internal struct BackgroundView: ExpoSwiftUI.View {
11
+ @ObservedObject var props: BackgroundViewProps
12
+
13
+ var body: some View {
14
+ baseContent
15
+ .background(alignment: props.alignment?.toAlignment() ?? .center) {
16
+ backgroundContent
17
+ }
18
+ }
19
+
20
+ @ViewBuilder
21
+ private var baseContent: some View {
22
+ ForEach(props.children?.withoutSlots() ?? [], id: \.id) { child in
23
+ let view: any View = child.childView
24
+ AnyView(view)
25
+ }
26
+ }
27
+
28
+ @ViewBuilder
29
+ private var backgroundContent: some View {
30
+ if let content = props.children?.slot("content") {
31
+ content
32
+ }
33
+ }
34
+ }
@@ -49,7 +49,7 @@ struct ColorPickerView: ExpoSwiftUI.View {
49
49
  components.count > 1 ? components[1] : components[0],
50
50
  components.count > 2 ? components[2] : components[0],
51
51
  newColor.cgColor.alpha
52
- ].map { Int(max(0, min(255, $0 * 255))) }
52
+ ].map { Int(max(0, min(255, ($0 * 255).rounded()))) }
53
53
 
54
54
  let format = supportsOpacity ? "#%02X%02X%02X%02X" : "#%02X%02X%02X"
55
55
  return String(format: format, rgba[0], rgba[1], rgba[2], supportsOpacity ? rgba[3] : 255)
@@ -10,6 +10,9 @@ public final class ExpoUIModule: Module {
10
10
  View(RNHostView.self)
11
11
 
12
12
  OnDestroy {
13
+ // Clear all registered content origins when the module is destroyed
14
+ ContentOriginRegistry.clearAll()
15
+
13
16
  Task { @MainActor in
14
17
  NamespaceRegistry.shared.removeAll()
15
18
  }
@@ -190,6 +193,7 @@ public final class ExpoUIModule: Module {
190
193
  ExpoUIView(DividerView.self)
191
194
  ExpoUIView(PopoverView.self)
192
195
  ExpoUIView(OverlayView.self)
196
+ ExpoUIView(BackgroundView.self)
193
197
  ExpoUIView(MaskView.self)
194
198
  ExpoUIView(GridView.self)
195
199
  ExpoUIView(AccessoryWidgetBackgroundView.self)
@@ -3,6 +3,11 @@
3
3
  import SwiftUI
4
4
  import ExpoModulesCore
5
5
 
6
+ /// Coordinate space anchored at the `Host`, so hosted React Native views can report where SwiftUI
7
+ /// actually placed them. Name it last in the chain: Yoga measures a hosted view from the `Host`
8
+ /// component view, so any `Host` inset or alignment has to be inside this space, not outside it.
9
+ internal let expoHostCoordinateSpace = "expo.ui.host"
10
+
6
11
  internal enum ExpoColorScheme: String, Enumerable {
7
12
  case light
8
13
  case dark
@@ -68,6 +73,7 @@ struct HostView: ExpoSwiftUI.View, ExpoSwiftUI.WithHostingView {
68
73
  globalEventDispatcher: props.globalEventDispatcher
69
74
  )
70
75
  .modifier(GeometryChangeModifier(props: props))
76
+ .coordinateSpace(name: expoHostCoordinateSpace)
71
77
  } else {
72
78
  ZStack(alignment: alignment) {
73
79
  Children()
@@ -82,6 +88,7 @@ struct HostView: ExpoSwiftUI.View, ExpoSwiftUI.WithHostingView {
82
88
  globalEventDispatcher: props.globalEventDispatcher
83
89
  )
84
90
  .modifier(GeometryChangeModifier(props: props))
91
+ .coordinateSpace(name: expoHostCoordinateSpace)
85
92
  }
86
93
  }
87
94
 
@@ -1034,6 +1034,50 @@ internal struct ListRowSpacing: ViewModifier, Record {
1034
1034
  }
1035
1035
  }
1036
1036
 
1037
+ internal enum AlignmentGuideOptions: String, Enumerable {
1038
+ case leading
1039
+ case center
1040
+ case trailing
1041
+ case listRowSeparatorLeading
1042
+ case listRowSeparatorTrailing
1043
+
1044
+ var horizontalAlignment: HorizontalAlignment? {
1045
+ switch self {
1046
+ case .leading:
1047
+ return .leading
1048
+ case .center:
1049
+ return .center
1050
+ case .trailing:
1051
+ return .trailing
1052
+ case .listRowSeparatorLeading:
1053
+ #if os(tvOS)
1054
+ return nil
1055
+ #else
1056
+ return .listRowSeparatorLeading
1057
+ #endif
1058
+ case .listRowSeparatorTrailing:
1059
+ #if os(tvOS)
1060
+ return nil
1061
+ #else
1062
+ return .listRowSeparatorTrailing
1063
+ #endif
1064
+ }
1065
+ }
1066
+ }
1067
+
1068
+ internal struct AlignmentGuideModifier: ViewModifier, Record {
1069
+ @Field var guide: AlignmentGuideOptions = .leading
1070
+ @Field var value: Double = 0
1071
+
1072
+ func body(content: Content) -> some View {
1073
+ if let alignment = guide.horizontalAlignment {
1074
+ content.alignmentGuide(alignment) { _ in CGFloat(value) }
1075
+ } else {
1076
+ content
1077
+ }
1078
+ }
1079
+ }
1080
+
1037
1081
  internal enum TextTruncationModeTypes: String, Enumerable {
1038
1082
  case head
1039
1083
  case middle
@@ -2042,6 +2086,10 @@ extension ViewModifierRegistry {
2042
2086
  return try ListRowSpacing(from: params, appContext: appContext)
2043
2087
  }
2044
2088
 
2089
+ register("alignmentGuide") { params, appContext, _ in
2090
+ return try AlignmentGuideModifier(from: params, appContext: appContext)
2091
+ }
2092
+
2045
2093
  register("truncationMode") { params, appContext, _ in
2046
2094
  return try TextTruncationMode(from: params, appContext: appContext)
2047
2095
  }
@@ -5,22 +5,55 @@ import ExpoModulesCore
5
5
 
6
6
  internal final class RNHostViewProps: ExpoSwiftUI.ViewProps {
7
7
  @Field var matchContents: Bool = false
8
+ /**
9
+ Whether this view owns its subtree's touches and is the origin its content is measured from. Set
10
+ by the JavaScript side for content presented in its own view controller — see `RNHostView.tsx`,
11
+ which reads it from the sheet or popover presenting the content.
12
+
13
+ Also read by `ExpoViewShadowNode` in C++, which turns it into the `RootNodeKind` trait so
14
+ `measure()` stops its ancestor walk here.
15
+ */
16
+ @Field var layoutRoot: Bool = false
8
17
  }
9
18
 
19
+ // Touches and `measure()` must agree on a coordinate space. Which space depends on where the
20
+ // content sits:
21
+ // Normal tree:
22
+ // The surface root above us already dispatches, in surface coordinates. We attach
23
+ // nothing and publish a content origin, so `measure()` matches those touches.
24
+ // Sheet, popover:
25
+ // Presented in its own view controller, so nothing above dispatches and the
26
+ // content would get no touches at all. We attach our own handler, and
27
+ // `layoutRoot` measures from this view — the space those touches arrive in.
28
+ //
29
+ // Attaching a handler in the normal tree would give the subtree two streams in two spaces: UIKit
30
+ // delivers a touch to the hit view and every ancestor, and the root's cannot be suppressed from
31
+ // below, so presses would cancel on any movement.
10
32
  struct RNHostView: ExpoSwiftUI.View {
11
33
 
12
34
  @ObservedObject var props: RNHostViewProps
13
- // Owns the RCTSurfaceTouchHandler we attach to the hosted RN view so it is detached again when
14
- // this host disappears.
15
35
  @StateObject private var touchHandler = RNHostTouchHandler()
16
36
 
17
37
  var body: some View {
38
+ hostedContent
39
+ .modifier(
40
+ PublishContentOriginModifier(
41
+ shadowNodeProxy: props.shadowNodeProxy,
42
+ isEnabled: !props.layoutRoot
43
+ )
44
+ )
45
+ }
46
+
47
+ @ViewBuilder
48
+ private var hostedContent: some View {
18
49
  if props.matchContents, let childUIView = firstChildUIView {
19
50
  ApplySizeFromYogaNode(childUIView: childUIView) {
20
51
  Children()
21
52
  }
22
53
  .onAppear {
23
- touchHandler.attach(to: childUIView)
54
+ if props.layoutRoot {
55
+ touchHandler.attach(to: childUIView)
56
+ }
24
57
  }
25
58
  .onDisappear {
26
59
  touchHandler.detach()
@@ -30,12 +63,17 @@ struct RNHostView: ExpoSwiftUI.View {
30
63
  // natural size instead of falling into the fill branch below, which would
31
64
  // stretch a self-sizing SwiftUI view to fill its container.
32
65
  Children()
66
+ } else if props.children?.isEmpty ?? true {
67
+ // Nothing is mounted yet (e.g. a hosted RN `Modal` renders null until `visible` is true).
68
+ // Render nothing instead of an empty fill frame, which would take up space in the
69
+ // surrounding SwiftUI container - e.g. a spurious empty row in a `Form`'s `Section`.
70
+ EmptyView()
33
71
  } else {
34
72
  Children()
35
73
  .frame(maxWidth: .infinity, maxHeight: .infinity)
36
74
  .modifier(ReportSizeToYogaNodeModifier(shadowNodeProxy: props.shadowNodeProxy))
37
75
  .onAppear {
38
- if let view = firstChildUIView {
76
+ if props.layoutRoot, let view = firstChildUIView {
39
77
  touchHandler.attach(to: view)
40
78
  }
41
79
  }
@@ -50,6 +88,29 @@ struct RNHostView: ExpoSwiftUI.View {
50
88
  }
51
89
  }
52
90
 
91
+ // Publishes where SwiftUI placed this view inside its `Host`, so `measure()` reports the position
92
+ // the hosted content actually occupies.
93
+ private struct PublishContentOriginModifier: ViewModifier {
94
+ let shadowNodeProxy: ExpoSwiftUI.ShadowNodeProxy
95
+ let isEnabled: Bool
96
+
97
+ func body(content: Content) -> some View {
98
+ if isEnabled {
99
+ content
100
+ .onGeometryChange(for: CGRect.self) { proxy in
101
+ proxy.frame(in: .named(expoHostCoordinateSpace))
102
+ } action: { frame in
103
+ shadowNodeProxy.setContentOrigin?(frame.origin)
104
+ }
105
+ .onDisappear {
106
+ shadowNodeProxy.clearContentOrigin?()
107
+ }
108
+ } else {
109
+ content
110
+ }
111
+ }
112
+ }
113
+
53
114
  // Tracks the `RCTSurfaceTouchHandler` attached to a hosted RN view so it can be detached when the
54
115
  // `RNHostView` disappears, instead of leaking onto the recycled component view.
55
116
  private final class RNHostTouchHandler: ObservableObject {
@@ -0,0 +1 @@
1
+ b873eba373a618838203ac4021d4694eaf842a0114c10a5925cd0b68c69df887
@@ -0,0 +1 @@
1
+ 7f85f310231cb704750cc75032268dda0fffff171528345c140fed39eb134be565c867ef329d092c1a128a88d6657576fb6e53b4009d40b8c465724ede556d08
@@ -0,0 +1 @@
1
+ 6aaf95d2f756b71ada1992a1a74bdfb36146fb94
@@ -0,0 +1 @@
1
+ 319460f26a7e44bc448ec15b0a2a60c28518cc6f3b38eaabc793d5edd69d4895
@@ -0,0 +1 @@
1
+ 3e051539308c1cadbcf965de44aabe9360dbdce57508d9ee0da9b2c465e08dbd5eb65f936deabea9dbd47964e7e445347fbdb601962e13379338b1222937aeb8
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "expo.modules.ui",
5
5
  "module": "expo.modules.ui",
6
- "version": "57.0.12",
6
+ "version": "57.0.14",
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-57.0.12.aar",
28
- "url": "expo.modules.ui-57.0.12.aar",
29
- "size": 1988885,
30
- "sha512": "8feb6c5213343355b543cddfedde01251c5a8a9067aa01efb89fe663b2a0e04f3284ab62ed2c9a2f8e65305691f61dd248ba2fdbc3dc7415c5d09ced6425edd1",
31
- "sha256": "cdc531cad279eabcfce2c71e778614be0e16c45c77222fe4fa51fcbd7991e30b",
32
- "sha1": "2ba19351886430ec818130eab431ce8143a56693",
33
- "md5": "4508cfcae86a661e2c66bbf15b5909b0"
27
+ "name": "expo.modules.ui-57.0.14.aar",
28
+ "url": "expo.modules.ui-57.0.14.aar",
29
+ "size": 1995898,
30
+ "sha512": "3e051539308c1cadbcf965de44aabe9360dbdce57508d9ee0da9b2c465e08dbd5eb65f936deabea9dbd47964e7e445347fbdb601962e13379338b1222937aeb8",
31
+ "sha256": "319460f26a7e44bc448ec15b0a2a60c28518cc6f3b38eaabc793d5edd69d4895",
32
+ "sha1": "6aaf95d2f756b71ada1992a1a74bdfb36146fb94",
33
+ "md5": "1540b06db518474f334df39b0fc8398d"
34
34
  }
35
35
  ]
36
36
  },
@@ -141,13 +141,13 @@
141
141
  ],
142
142
  "files": [
143
143
  {
144
- "name": "expo.modules.ui-57.0.12.aar",
145
- "url": "expo.modules.ui-57.0.12.aar",
146
- "size": 1988885,
147
- "sha512": "8feb6c5213343355b543cddfedde01251c5a8a9067aa01efb89fe663b2a0e04f3284ab62ed2c9a2f8e65305691f61dd248ba2fdbc3dc7415c5d09ced6425edd1",
148
- "sha256": "cdc531cad279eabcfce2c71e778614be0e16c45c77222fe4fa51fcbd7991e30b",
149
- "sha1": "2ba19351886430ec818130eab431ce8143a56693",
150
- "md5": "4508cfcae86a661e2c66bbf15b5909b0"
144
+ "name": "expo.modules.ui-57.0.14.aar",
145
+ "url": "expo.modules.ui-57.0.14.aar",
146
+ "size": 1995898,
147
+ "sha512": "3e051539308c1cadbcf965de44aabe9360dbdce57508d9ee0da9b2c465e08dbd5eb65f936deabea9dbd47964e7e445347fbdb601962e13379338b1222937aeb8",
148
+ "sha256": "319460f26a7e44bc448ec15b0a2a60c28518cc6f3b38eaabc793d5edd69d4895",
149
+ "sha1": "6aaf95d2f756b71ada1992a1a74bdfb36146fb94",
150
+ "md5": "1540b06db518474f334df39b0fc8398d"
151
151
  }
152
152
  ]
153
153
  },
@@ -161,13 +161,13 @@
161
161
  },
162
162
  "files": [
163
163
  {
164
- "name": "expo.modules.ui-57.0.12-sources.jar",
165
- "url": "expo.modules.ui-57.0.12-sources.jar",
166
- "size": 98169,
167
- "sha512": "bee3386af6f699916c5f3b09c72510621403743e5e887bf0e60d13142304a97964289f39f1fe79355ca9127cc02dfc88cf2d21bbfa4638ed4b9446de05030856",
168
- "sha256": "3f5266c79c694c7d3ae5a885827d2dfb4ae922a9f66fceca406cd7556b753ac0",
169
- "sha1": "dabe60c8f675eb6123187ef607915dccbeb79789",
170
- "md5": "46f030ed2d5faa9fc07df319df125512"
164
+ "name": "expo.modules.ui-57.0.14-sources.jar",
165
+ "url": "expo.modules.ui-57.0.14-sources.jar",
166
+ "size": 101264,
167
+ "sha512": "7f85f310231cb704750cc75032268dda0fffff171528345c140fed39eb134be565c867ef329d092c1a128a88d6657576fb6e53b4009d40b8c465724ede556d08",
168
+ "sha256": "b873eba373a618838203ac4021d4694eaf842a0114c10a5925cd0b68c69df887",
169
+ "sha1": "52d4523918d2d1e36704df643a721bc42831a30d",
170
+ "md5": "f7d54b0ae1f14df62dfcecff0d9bbbfc"
171
171
  }
172
172
  ]
173
173
  }
@@ -0,0 +1 @@
1
+ 4b12fa7cf2eafec047ae0bb4290fa9ea36c6a1a9
@@ -0,0 +1 @@
1
+ 4c860ed7fc9f4b1492ee6bd299f9c0881ae8286f3eb0bcb95790c7285c19cd58
@@ -0,0 +1 @@
1
+ ce1a1bea00c876f9666307b662e48a36d58f7dc4f26f5364c8039e542786d305d965855ef2b1832342fceca0c6e12bb87e906fb25a4ea41fe1da8d4b1585c459
@@ -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>57.0.12</version>
12
+ <version>57.0.14</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
+ 834f927d24513892b48b4a45afe0d0e0322d274c
@@ -0,0 +1 @@
1
+ 3f5e966c190b0b4a771b1e7498fd8d2d6227639ffdaa1ea746a8aad505469a8c
@@ -0,0 +1 @@
1
+ 3e6f229eb05b6c860730c16d6e3d5ca9c47eac8569f2d84bf8f925c547857fce65361e69ed56153b55527a5df3785243987d27b934cc46c50200974e62a7c28c
@@ -3,11 +3,11 @@
3
3
  <groupId>expo.modules.ui</groupId>
4
4
  <artifactId>expo.modules.ui</artifactId>
5
5
  <versioning>
6
- <latest>57.0.12</latest>
7
- <release>57.0.12</release>
6
+ <latest>57.0.14</latest>
7
+ <release>57.0.14</release>
8
8
  <versions>
9
- <version>57.0.12</version>
9
+ <version>57.0.14</version>
10
10
  </versions>
11
- <lastUpdated>20260820103851</lastUpdated>
11
+ <lastUpdated>20260826195105</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 990a1e6f470f0ae61d641c01c2510f97
1
+ 4dfe61c00978e656bb86f7a4aba692dd
@@ -1 +1 @@
1
- a6d138ba3ecd66801bb35f9d23a69cef22d0b0e8
1
+ b9406185faafd8465b9a6d8c48ab5f7f70546764
@@ -1 +1 @@
1
- d98cea313be8b245d8c8b9dd4455ddaa2f5259a8e9a55b19079afd698133e01e
1
+ 39b0c675409d452116a0df7c42ac801510989b59056cbac7611145c7e2548593
@@ -1 +1 @@
1
- 6d33dd52cf942431a652c01906b58f2765c791f457597f8757a98d8d6dfa2a2af5ed9715aca0c28ceb9ab615b01198d6126dd48f1745762560d41d845507f374
1
+ de8e79434bbdd397d0eba8e9679e265eb3f2b388de06555138c1a2c9e1f337b9ef0240ba566686cba658d7a7b501523141df379c83d1b35a44f0b6b94210046a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/ui",
3
- "version": "57.0.12",
3
+ "version": "57.0.14",
4
4
  "description": "A collection of UI components",
5
5
  "sideEffects": [
6
6
  "*.fx.js",
@@ -96,8 +96,8 @@
96
96
  "@types/react": "~19.2.0",
97
97
  "react-native-reanimated": "4.5.1",
98
98
  "react-native-worklets": "0.10.1",
99
- "expo": "57.0.15",
100
- "expo-module-scripts": "56.0.3"
99
+ "expo-module-scripts": "56.0.3",
100
+ "expo": "57.0.17"
101
101
  },
102
102
  "jest": {
103
103
  "preset": "expo-module-scripts"
@@ -121,7 +121,7 @@
121
121
  "optional": true
122
122
  }
123
123
  },
124
- "gitHead": "499024a441d67293aa60afcbe02051999a54f1bb",
124
+ "gitHead": "c300d2cc60c9e684e64f48d9bc90ea18a571d01d",
125
125
  "scripts": {
126
126
  "build": "expo-module build",
127
127
  "clean": "expo-module clean",
@@ -0,0 +1,22 @@
1
+ import { createContext, useContext, type ReactNode } from 'react';
2
+
3
+ export const PresentedContentContext = createContext(false);
4
+
5
+ /**
6
+ * Whether the surrounding content is presented in its own view controller — a sheet, a popover
7
+ * — rather than in the React Native surface.
8
+ *
9
+ * `RNHostView` needs this because nothing above such content dispatches React Native touches: the
10
+ * surface root is not one of its ancestors. A hosted view there has to dispatch its own touches and
11
+ * be the origin its content is measured from, and both of those come from a single `layoutRoot`
12
+ * prop.
13
+ *
14
+ * Defaults to `false`, so content that is not wrapped keeps deferring to the surface root.
15
+ */
16
+ export function useIsPresentedInOwnWindow(): boolean {
17
+ return useContext(PresentedContentContext);
18
+ }
19
+
20
+ export function PresentedContent({ children }: { children: ReactNode }) {
21
+ return <PresentedContentContext.Provider value>{children}</PresentedContentContext.Provider>;
22
+ }
@@ -77,13 +77,7 @@ export function PagerView(props: PagerViewProps) {
77
77
  const pages = Children.toArray(children)
78
78
  .filter((child): child is ReactElement => isValidElement(child))
79
79
  .map((child, index) => (
80
- <RNHostView
81
- key={child.key ?? String(index)}
82
- // Overlap pages at one origin so each page's RN shadow position matches
83
- // where Compose draws it; otherwise `measure()`-based hit-testing
84
- // (e.g. `Pressable`) misfires on pages after the first (#46386).
85
- style={StyleSheet.absoluteFill}
86
- modifiers={[fillMaxSize()]}>
80
+ <RNHostView key={child.key ?? String(index)} modifiers={[fillMaxSize()]}>
87
81
  <View style={styles.page} pointerEvents={index === settledPage ? 'auto' : 'none'}>
88
82
  {child}
89
83
  </View>
@@ -1,6 +1,7 @@
1
1
  import { requireNativeView } from 'expo';
2
2
  import { type ColorValue } from 'react-native';
3
3
 
4
+ import { PresentedContent } from '../../PresentedContentContext';
4
5
  import { type ViewEvent, type ModifierConfig, type DialogProperties } from '../../types';
5
6
  import { createViewModifierEventListener } from '../modifiers/utils';
6
7
 
@@ -123,7 +124,11 @@ function AlertDialogIcon(props: { children: React.ReactNode }) {
123
124
  */
124
125
  function AlertDialogComponent(props: AlertDialogProps) {
125
126
  const { children, ...restProps } = props;
126
- return <AlertDialogNativeView {...transformProps(restProps)}>{children}</AlertDialogNativeView>;
127
+ return (
128
+ <AlertDialogNativeView {...transformProps(restProps)}>
129
+ <PresentedContent>{children}</PresentedContent>
130
+ </AlertDialogNativeView>
131
+ );
127
132
  }
128
133
 
129
134
  AlertDialogComponent.Title = AlertDialogTitle;
@@ -1,5 +1,6 @@
1
1
  import { requireNativeView } from 'expo';
2
2
 
3
+ import { PresentedContent } from '../../PresentedContentContext';
3
4
  import { type ViewEvent, type ModifierConfig, type DialogProperties } from '../../types';
4
5
  import { createViewModifierEventListener } from '../modifiers/utils';
5
6
 
@@ -51,7 +52,12 @@ function transformProps(props: BasicAlertDialogProps): NativeBasicAlertDialogPro
51
52
  * Unlike `AlertDialog`, this component does not have structured title/text/buttons slots.
52
53
  */
53
54
  export function BasicAlertDialog(props: BasicAlertDialogProps) {
54
- return <BasicAlertDialogNativeView {...transformProps(props)} />;
55
+ const { children, ...rest } = props;
56
+ return (
57
+ <BasicAlertDialogNativeView {...transformProps(rest as BasicAlertDialogProps)}>
58
+ <PresentedContent>{children}</PresentedContent>
59
+ </BasicAlertDialogNativeView>
60
+ );
55
61
  }
56
62
 
57
63
  // Re-exported so the docs generator includes DialogProperties on the BasicAlertDialog API page.
@@ -2,6 +2,7 @@ import { requireNativeView } from 'expo';
2
2
  import type { ReactNode } from 'react';
3
3
  import type { StyleProp, ViewStyle, ColorValue } from 'react-native';
4
4
 
5
+ import { PresentedContent } from '../../PresentedContentContext';
5
6
  import type { ModifierConfig } from '../../types';
6
7
  import { createViewModifierEventListener } from '../modifiers/utils';
7
8
 
@@ -67,7 +68,12 @@ type NativeMenuProps = {
67
68
  * Children should be `DropdownMenuItem` components or other native views.
68
69
  */
69
70
  export function Items(props: { children: ReactNode }) {
70
- return <SlotNativeView slotName="items">{props.children}</SlotNativeView>;
71
+ // The items are presented in their own popup window; the trigger stays in the React Native surface.
72
+ return (
73
+ <SlotNativeView slotName="items">
74
+ <PresentedContent>{props.children}</PresentedContent>
75
+ </SlotNativeView>
76
+ );
71
77
  }
72
78
  Items.tag = 'Items';
73
79
 
@@ -2,6 +2,7 @@ import { requireNativeView } from 'expo';
2
2
  import type { ReactNode } from 'react';
3
3
  import { type ColorValue } from 'react-native';
4
4
 
5
+ import { PresentedContent } from '../../PresentedContentContext';
5
6
  import { type ModifierConfig } from '../../types';
6
7
  import { createViewModifierEventListener } from '../modifiers/utils';
7
8
 
@@ -48,7 +49,8 @@ export function ExposedDropdownMenu(props: ExposedDropdownMenuProps) {
48
49
  modifiers={modifiers}
49
50
  {...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
50
51
  {...restProps}>
51
- {children}
52
+ {/* The menu is a popup in its own window. The anchor stays in `ExposedDropdownMenuBox`. */}
53
+ <PresentedContent>{children}</PresentedContent>
52
54
  </NativeView>
53
55
  );
54
56
  }