@expo/ui 56.0.7 → 56.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 (208) hide show
  1. package/CHANGELOG.md +39 -1
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +44 -3
  4. package/android/src/main/java/expo/modules/ui/HostView.kt +2 -0
  5. package/android/src/main/java/expo/modules/ui/LoadingView.kt +80 -0
  6. package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +50 -4
  7. package/android/src/main/java/expo/modules/ui/RNHostView.kt +8 -3
  8. package/android/src/main/java/expo/modules/ui/ShadowNodeSyncFlush.kt +28 -0
  9. package/android/src/main/java/expo/modules/ui/SnackbarView.kt +126 -0
  10. package/android/src/main/java/expo/modules/ui/state/ObservableState.kt +10 -0
  11. package/assets/keyboard_arrow_down.xml +10 -0
  12. package/build/State/useNativeState.d.ts +32 -3
  13. package/build/State/useNativeState.d.ts.map +1 -1
  14. package/build/community/bottom-sheet/BottomSheet.ios.d.ts.map +1 -1
  15. package/build/community/menu/MenuView.android.d.ts +16 -0
  16. package/build/community/menu/MenuView.android.d.ts.map +1 -0
  17. package/build/community/menu/MenuView.d.ts +19 -0
  18. package/build/community/menu/MenuView.d.ts.map +1 -0
  19. package/build/community/menu/MenuView.ios.d.ts +10 -0
  20. package/build/community/menu/MenuView.ios.d.ts.map +1 -0
  21. package/build/community/menu/index.d.ts +5 -0
  22. package/build/community/menu/index.d.ts.map +1 -0
  23. package/build/community/menu/types.d.ts +166 -0
  24. package/build/community/menu/types.d.ts.map +1 -0
  25. package/build/jetpack-compose/LoadingIndicator/index.d.ts +41 -0
  26. package/build/jetpack-compose/LoadingIndicator/index.d.ts.map +1 -0
  27. package/build/jetpack-compose/Snackbar/index.d.ts +94 -0
  28. package/build/jetpack-compose/Snackbar/index.d.ts.map +1 -0
  29. package/build/jetpack-compose/index.d.ts +2 -0
  30. package/build/jetpack-compose/index.d.ts.map +1 -1
  31. package/build/jetpack-compose/modifiers/index.d.ts +21 -2
  32. package/build/jetpack-compose/modifiers/index.d.ts.map +1 -1
  33. package/build/swift-ui/Alert/index.d.ts +42 -0
  34. package/build/swift-ui/Alert/index.d.ts.map +1 -0
  35. package/build/swift-ui/BottomSheet/index.d.ts +5 -1
  36. package/build/swift-ui/BottomSheet/index.d.ts.map +1 -1
  37. package/build/swift-ui/SlotView.d.ts +5 -2
  38. package/build/swift-ui/SlotView.d.ts.map +1 -1
  39. package/build/swift-ui/SwipeActions/index.d.ts +38 -0
  40. package/build/swift-ui/SwipeActions/index.d.ts.map +1 -0
  41. package/build/swift-ui/index.d.ts +3 -0
  42. package/build/swift-ui/index.d.ts.map +1 -1
  43. package/build/swift-ui/modifiers/index.d.ts +3 -1
  44. package/build/swift-ui/modifiers/index.d.ts.map +1 -1
  45. package/build/swift-ui/modifiers/symbolEffect.d.ts +103 -0
  46. package/build/swift-ui/modifiers/symbolEffect.d.ts.map +1 -0
  47. package/build/swift-ui/withAnimation.d.ts +26 -0
  48. package/build/swift-ui/withAnimation.d.ts.map +1 -0
  49. package/build/universal/BottomSheet/index.android.d.ts +1 -1
  50. package/build/universal/BottomSheet/index.android.d.ts.map +1 -1
  51. package/build/universal/BottomSheet/index.d.ts +1 -1
  52. package/build/universal/BottomSheet/index.d.ts.map +1 -1
  53. package/build/universal/BottomSheet/index.ios.d.ts +1 -1
  54. package/build/universal/BottomSheet/index.ios.d.ts.map +1 -1
  55. package/build/universal/BottomSheet/types.d.ts +27 -0
  56. package/build/universal/BottomSheet/types.d.ts.map +1 -1
  57. package/build/universal/Collapsible/index.android.d.ts +8 -0
  58. package/build/universal/Collapsible/index.android.d.ts.map +1 -0
  59. package/build/universal/Collapsible/index.d.ts +8 -0
  60. package/build/universal/Collapsible/index.d.ts.map +1 -0
  61. package/build/universal/Collapsible/index.ios.d.ts +7 -0
  62. package/build/universal/Collapsible/index.ios.d.ts.map +1 -0
  63. package/build/universal/Collapsible/types.d.ts +23 -0
  64. package/build/universal/Collapsible/types.d.ts.map +1 -0
  65. package/build/universal/Column/index.d.ts.map +1 -1
  66. package/build/universal/Host/index.d.ts +5 -7
  67. package/build/universal/Host/index.d.ts.map +1 -1
  68. package/build/universal/Host/types.d.ts +72 -0
  69. package/build/universal/Host/types.d.ts.map +1 -0
  70. package/build/universal/List/index.android.d.ts +9 -0
  71. package/build/universal/List/index.android.d.ts.map +1 -0
  72. package/build/universal/List/index.d.ts +8 -0
  73. package/build/universal/List/index.d.ts.map +1 -0
  74. package/build/universal/List/index.ios.d.ts +8 -0
  75. package/build/universal/List/index.ios.d.ts.map +1 -0
  76. package/build/universal/List/types.d.ts +26 -0
  77. package/build/universal/List/types.d.ts.map +1 -0
  78. package/build/universal/ListItem/ListItem.android.d.ts +8 -0
  79. package/build/universal/ListItem/ListItem.android.d.ts.map +1 -0
  80. package/build/universal/ListItem/ListItem.d.ts +9 -0
  81. package/build/universal/ListItem/ListItem.d.ts.map +1 -0
  82. package/build/universal/ListItem/ListItem.ios.d.ts +8 -0
  83. package/build/universal/ListItem/ListItem.ios.d.ts.map +1 -0
  84. package/build/universal/ListItem/ListItemSlots.d.ts +21 -0
  85. package/build/universal/ListItem/ListItemSlots.d.ts.map +1 -0
  86. package/build/universal/ListItem/index.d.ts +10 -0
  87. package/build/universal/ListItem/index.d.ts.map +1 -0
  88. package/build/universal/ListItem/types.d.ts +59 -0
  89. package/build/universal/ListItem/types.d.ts.map +1 -0
  90. package/build/universal/Picker/Picker.android.d.ts +9 -0
  91. package/build/universal/Picker/Picker.android.d.ts.map +1 -0
  92. package/build/universal/Picker/Picker.d.ts +8 -0
  93. package/build/universal/Picker/Picker.d.ts.map +1 -0
  94. package/build/universal/Picker/Picker.ios.d.ts +9 -0
  95. package/build/universal/Picker/Picker.ios.d.ts.map +1 -0
  96. package/build/universal/Picker/PickerItem.d.ts +9 -0
  97. package/build/universal/Picker/PickerItem.d.ts.map +1 -0
  98. package/build/universal/Picker/index.d.ts +8 -0
  99. package/build/universal/Picker/index.d.ts.map +1 -0
  100. package/build/universal/Picker/types.d.ts +69 -0
  101. package/build/universal/Picker/types.d.ts.map +1 -0
  102. package/build/universal/index.d.ts +4 -0
  103. package/build/universal/index.d.ts.map +1 -1
  104. package/expo-module.config.json +1 -1
  105. package/ios/Alert/Alert.swift +56 -0
  106. package/ios/Alert/AlertProps.swift +8 -0
  107. package/ios/BottomSheetView.swift +4 -1
  108. package/ios/ExpoUIModule.swift +43 -1
  109. package/ios/ExpoUITouchHandlerHelper.h +4 -1
  110. package/ios/ExpoUITouchHandlerHelper.mm +1 -0
  111. package/ios/Modifiers/AnimationConfig.swift +109 -0
  112. package/ios/Modifiers/SwipeActionsModifier.swift +97 -0
  113. package/ios/Modifiers/SymbolEffectModifier.swift +452 -0
  114. package/ios/Modifiers/ViewModifierRegistry.swift +5 -112
  115. package/ios/SlotView.swift +5 -0
  116. package/ios/State/ObservableState.swift +12 -1
  117. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7-sources.jar → 56.0.9/expo.modules.ui-56.0.9-sources.jar} +0 -0
  118. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.md5 +1 -0
  119. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha1 +1 -0
  120. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha256 +1 -0
  121. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha512 +1 -0
  122. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar +0 -0
  123. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.md5 +1 -0
  124. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha1 +1 -0
  125. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha256 +1 -0
  126. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha512 +1 -0
  127. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7.module → 56.0.9/expo.modules.ui-56.0.9.module} +22 -22
  128. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.md5 +1 -0
  129. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha1 +1 -0
  130. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha256 +1 -0
  131. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha512 +1 -0
  132. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7.pom → 56.0.9/expo.modules.ui-56.0.9.pom} +1 -1
  133. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.md5 +1 -0
  134. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.sha1 +1 -0
  135. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.sha256 +1 -0
  136. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.sha512 +1 -0
  137. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
  138. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
  139. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
  140. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
  141. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
  142. package/package.json +7 -3
  143. package/src/State/useNativeState.ts +70 -10
  144. package/src/community/bottom-sheet/BottomSheet.ios.tsx +0 -17
  145. package/src/community/menu/MenuView.android.tsx +224 -0
  146. package/src/community/menu/MenuView.ios.tsx +149 -0
  147. package/src/community/menu/MenuView.tsx +36 -0
  148. package/src/community/menu/index.tsx +14 -0
  149. package/src/community/menu/types.tsx +171 -0
  150. package/src/jetpack-compose/LoadingIndicator/index.tsx +92 -0
  151. package/src/jetpack-compose/Snackbar/index.tsx +135 -0
  152. package/src/jetpack-compose/index.ts +2 -0
  153. package/src/jetpack-compose/modifiers/index.ts +30 -2
  154. package/src/swift-ui/Alert/index.tsx +87 -0
  155. package/src/swift-ui/BottomSheet/index.tsx +32 -15
  156. package/src/swift-ui/SlotView.tsx +17 -4
  157. package/src/swift-ui/SwipeActions/index.tsx +73 -0
  158. package/src/swift-ui/index.tsx +3 -0
  159. package/src/swift-ui/modifiers/index.ts +3 -0
  160. package/src/swift-ui/modifiers/symbolEffect.ts +181 -0
  161. package/src/swift-ui/withAnimation.ts +71 -0
  162. package/src/ts-declarations/react-native-web.d.ts +27 -0
  163. package/src/universal/BottomSheet/index.android.tsx +27 -3
  164. package/src/universal/BottomSheet/index.ios.tsx +30 -12
  165. package/src/universal/BottomSheet/index.tsx +46 -4
  166. package/src/universal/BottomSheet/types.ts +25 -0
  167. package/src/universal/Collapsible/index.android.tsx +72 -0
  168. package/src/universal/Collapsible/index.ios.tsx +16 -0
  169. package/src/universal/Collapsible/index.tsx +58 -0
  170. package/src/universal/Collapsible/types.ts +25 -0
  171. package/src/universal/Column/index.tsx +3 -1
  172. package/src/universal/Host/index.tsx +69 -5
  173. package/src/universal/Host/types.ts +70 -0
  174. package/src/universal/List/index.android.tsx +44 -0
  175. package/src/universal/List/index.ios.tsx +19 -0
  176. package/src/universal/List/index.tsx +26 -0
  177. package/src/universal/List/types.ts +28 -0
  178. package/src/universal/ListItem/ListItem.android.tsx +52 -0
  179. package/src/universal/ListItem/ListItem.ios.tsx +58 -0
  180. package/src/universal/ListItem/ListItem.tsx +72 -0
  181. package/src/universal/ListItem/ListItemSlots.tsx +66 -0
  182. package/src/universal/ListItem/index.ts +15 -0
  183. package/src/universal/ListItem/types.ts +67 -0
  184. package/src/universal/Picker/Picker.android.tsx +69 -0
  185. package/src/universal/Picker/Picker.ios.tsx +45 -0
  186. package/src/universal/Picker/Picker.tsx +52 -0
  187. package/src/universal/Picker/PickerItem.tsx +27 -0
  188. package/src/universal/Picker/index.ts +11 -0
  189. package/src/universal/Picker/types.ts +79 -0
  190. package/src/universal/index.ts +4 -0
  191. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.md5 +0 -1
  192. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha1 +0 -1
  193. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha256 +0 -1
  194. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha512 +0 -1
  195. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar +0 -0
  196. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.md5 +0 -1
  197. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha1 +0 -1
  198. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha256 +0 -1
  199. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha512 +0 -1
  200. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.md5 +0 -1
  201. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha1 +0 -1
  202. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha256 +0 -1
  203. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha512 +0 -1
  204. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.md5 +0 -1
  205. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha1 +0 -1
  206. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha256 +0 -1
  207. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha512 +0 -1
  208. package/src/community/bottom-sheet/CLAUDE.md +0 -55
@@ -13,7 +13,18 @@ import SwiftUI
13
13
  * Toggle(label, isOn: state.binding(false))
14
14
  */
15
15
  internal class ObservableState: SharedObject, ObservableObject {
16
- @Published var value: Any?
16
+ var onChange: WorkletCallback?
17
+ private var isNotifying = false
18
+
19
+ @Published var value: Any? {
20
+ didSet {
21
+ // Skip re-invoking onChange if state.value was written from inside onChange.
22
+ guard !isNotifying else { return }
23
+ isNotifying = true
24
+ defer { isNotifying = false }
25
+ onChange?.invoke(arguments: [value ?? NSNull()])
26
+ }
27
+ }
17
28
 
18
29
  init(value: Any?) {
19
30
  self.value = value
@@ -0,0 +1 @@
1
+ b68d51962848180ac90fcb20a9766fabd72327ad
@@ -0,0 +1 @@
1
+ e068f417d7a302f7d37e1d8648b7f61d2da46d215aede6ad991e35f780e794ea
@@ -0,0 +1 @@
1
+ 408e70adeb3b30e509e418a2a6edbd5afb888a27f8fcd5c04032a1089ef32c4483e542854cd1621a74aa2763094cd2e6ba98b30e99e213dd06734167e6d4083c
@@ -0,0 +1 @@
1
+ 4631f8e63a9536ef63c03c7666fbaa0e5a4f60a1
@@ -0,0 +1 @@
1
+ 7f2175675f65b6caaf5ce6580cdd24a10f208ae6d80b894e4460796fe2f0dc05
@@ -0,0 +1 @@
1
+ ba0dfa2c02b2ad1f248bfe43a5a922a95dbb83c493eb23cd8d3b98f3e790d9be19133002ac2ab408f3a9268af3c5718072f0646c2e13b0ce2d01b8198ae8ccc6
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "expo.modules.ui",
5
5
  "module": "expo.modules.ui",
6
- "version": "56.0.7",
6
+ "version": "56.0.9",
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-56.0.7.aar",
28
- "url": "expo.modules.ui-56.0.7.aar",
29
- "size": 1742882,
30
- "sha512": "2214ac6df49634ec222a3563eb91161f0ba5977ea600f354473f9dd5d166dd79b5230c634d59c15fe027d77f9010fd3d984718d4c392adf444acf687e40e076e",
31
- "sha256": "05e8833b0c8b22442fa1d70cd203ec9f986fd4e9d8541393c843779bca1bed6a",
32
- "sha1": "63505c031167b651fcd2b3ed1cddbcb5a014bfa8",
33
- "md5": "ea2684e30595f6e153476b3bd38b40f7"
27
+ "name": "expo.modules.ui-56.0.9.aar",
28
+ "url": "expo.modules.ui-56.0.9.aar",
29
+ "size": 1805504,
30
+ "sha512": "ba0dfa2c02b2ad1f248bfe43a5a922a95dbb83c493eb23cd8d3b98f3e790d9be19133002ac2ab408f3a9268af3c5718072f0646c2e13b0ce2d01b8198ae8ccc6",
31
+ "sha256": "7f2175675f65b6caaf5ce6580cdd24a10f208ae6d80b894e4460796fe2f0dc05",
32
+ "sha1": "4631f8e63a9536ef63c03c7666fbaa0e5a4f60a1",
33
+ "md5": "1375a9ac8dc803a405dd2fa39159a0bc"
34
34
  }
35
35
  ]
36
36
  },
@@ -141,13 +141,13 @@
141
141
  ],
142
142
  "files": [
143
143
  {
144
- "name": "expo.modules.ui-56.0.7.aar",
145
- "url": "expo.modules.ui-56.0.7.aar",
146
- "size": 1742882,
147
- "sha512": "2214ac6df49634ec222a3563eb91161f0ba5977ea600f354473f9dd5d166dd79b5230c634d59c15fe027d77f9010fd3d984718d4c392adf444acf687e40e076e",
148
- "sha256": "05e8833b0c8b22442fa1d70cd203ec9f986fd4e9d8541393c843779bca1bed6a",
149
- "sha1": "63505c031167b651fcd2b3ed1cddbcb5a014bfa8",
150
- "md5": "ea2684e30595f6e153476b3bd38b40f7"
144
+ "name": "expo.modules.ui-56.0.9.aar",
145
+ "url": "expo.modules.ui-56.0.9.aar",
146
+ "size": 1805504,
147
+ "sha512": "ba0dfa2c02b2ad1f248bfe43a5a922a95dbb83c493eb23cd8d3b98f3e790d9be19133002ac2ab408f3a9268af3c5718072f0646c2e13b0ce2d01b8198ae8ccc6",
148
+ "sha256": "7f2175675f65b6caaf5ce6580cdd24a10f208ae6d80b894e4460796fe2f0dc05",
149
+ "sha1": "4631f8e63a9536ef63c03c7666fbaa0e5a4f60a1",
150
+ "md5": "1375a9ac8dc803a405dd2fa39159a0bc"
151
151
  }
152
152
  ]
153
153
  },
@@ -161,13 +161,13 @@
161
161
  },
162
162
  "files": [
163
163
  {
164
- "name": "expo.modules.ui-56.0.7-sources.jar",
165
- "url": "expo.modules.ui-56.0.7-sources.jar",
166
- "size": 82267,
167
- "sha512": "26e067865e2bbdd9f770d670f8212c2a309bee05009f722931b339ca9f76c235bbed2286a876d9c7a7b0ddb0e4b152617031f487c047ae78d0672ecc2649c6be",
168
- "sha256": "213a1693673392a710d27fef37d99ef030c8a8783b4ccaa971ea914588dc5241",
169
- "sha1": "a534f795e8ea46629011b2f8939608619b954ff1",
170
- "md5": "f6beb7095321eea7da6845fa478235b0"
164
+ "name": "expo.modules.ui-56.0.9-sources.jar",
165
+ "url": "expo.modules.ui-56.0.9-sources.jar",
166
+ "size": 86330,
167
+ "sha512": "408e70adeb3b30e509e418a2a6edbd5afb888a27f8fcd5c04032a1089ef32c4483e542854cd1621a74aa2763094cd2e6ba98b30e99e213dd06734167e6d4083c",
168
+ "sha256": "e068f417d7a302f7d37e1d8648b7f61d2da46d215aede6ad991e35f780e794ea",
169
+ "sha1": "b68d51962848180ac90fcb20a9766fabd72327ad",
170
+ "md5": "792086c87c80e11e11b3e96d4b0a27d5"
171
171
  }
172
172
  ]
173
173
  }
@@ -0,0 +1 @@
1
+ 9fc748a23b388982628ba7ea8fb7beb7ce8673b9
@@ -0,0 +1 @@
1
+ 824aeb287c84a0ae7a903bbcd2ed28e02606bb63ff7b752f67f12469461f5b75
@@ -0,0 +1 @@
1
+ 7a87a1877c5555ab2b67f662d16481ef097240be1ac1ffaf3866ce167bf086cd272977ed945aafaf0143ee82c0fba1af5a5edc9fd6dd3715976708eea8beb901
@@ -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>56.0.7</version>
12
+ <version>56.0.9</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
+ 5f7de9f68a75a8180e441e1d8f88d38db511ea4d
@@ -0,0 +1 @@
1
+ d8cabffaed7874f9cdaa99bdb3148847466647b3d8e38175a0d6129f42fc54ea
@@ -0,0 +1 @@
1
+ d1b858cfe33845e3584fe8fe75da774a06c2d6ddef4c44e59671a832d9c5df04dad92780c7aa6f1a0183e337e4998d89598f6c08e91fda083ae0cd5c4a7cfb37
@@ -3,11 +3,11 @@
3
3
  <groupId>expo.modules.ui</groupId>
4
4
  <artifactId>expo.modules.ui</artifactId>
5
5
  <versioning>
6
- <latest>56.0.7</latest>
7
- <release>56.0.7</release>
6
+ <latest>56.0.9</latest>
7
+ <release>56.0.9</release>
8
8
  <versions>
9
- <version>56.0.7</version>
9
+ <version>56.0.9</version>
10
10
  </versions>
11
- <lastUpdated>20260513235023</lastUpdated>
11
+ <lastUpdated>20260519105316</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 64a2879e004360e655bef65bb9d431bd
1
+ 8beb24b746da04389648d65442b3fb27
@@ -1 +1 @@
1
- fd140bdfc96ce3c091dc1ef092f168c76a3cb9a0
1
+ 8f014cd5ad5596a8660865918f34d57e96318181
@@ -1 +1 @@
1
- d0e48014168bdeb917b14bc8af57d4f31668e40765bbf6e211a285109a1881f9
1
+ 00837d4c8ed40055be180e9910d9ed846227ab6602aef92f5f397e03348985db
@@ -1 +1 @@
1
- 4b66f59083f73dd1eb00a28589bfd4f6d0f124918bbd8687af190b54c8264f1ea9399b767be30fc04e99dc584d676ef455ebbf455d97033a0beb408c0cc106e5
1
+ 400a09733b7b0b618213ee16be214463bc22a236e1073bd075d8e75a3ca278987524685812324ef7b2b52a0ec4be6a0ccd056dfc9e1f059080ba8c4594aa811f
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/ui",
3
- "version": "56.0.7",
3
+ "version": "56.0.9",
4
4
  "description": "A collection of UI components",
5
5
  "sideEffects": [
6
6
  "*.fx.js"
@@ -51,6 +51,10 @@
51
51
  "types": "./build/community/masked-view/index.d.ts",
52
52
  "default": "./src/community/masked-view/index.tsx"
53
53
  },
54
+ "./community/menu": {
55
+ "types": "./build/community/menu/index.d.ts",
56
+ "default": "./src/community/menu/index.tsx"
57
+ },
54
58
  "./babel-plugin": {
55
59
  "types": "./plugin/babel-plugin.d.ts",
56
60
  "default": "./plugin/babel-plugin.js"
@@ -87,7 +91,7 @@
87
91
  "@types/react": "~19.2.0",
88
92
  "react-native-reanimated": "4.3.1",
89
93
  "react-native-worklets": "0.8.3",
90
- "expo": "56.0.0-preview.11",
94
+ "expo": "56.0.0-preview.13",
91
95
  "expo-module-scripts": "56.0.2"
92
96
  },
93
97
  "jest": {
@@ -116,7 +120,7 @@
116
120
  "optional": true
117
121
  }
118
122
  },
119
- "gitHead": "51c27fce31a5b3a877a4b05d832dabf4a99db5e1",
123
+ "gitHead": "290368bc41026449a05a4ebf991b85c3a2fb0e3a",
120
124
  "scripts": {
121
125
  "build": "expo-module build",
122
126
  "clean": "expo-module clean",
@@ -12,11 +12,39 @@ const ExpoUI = requireNativeModule('ExpoUI');
12
12
  */
13
13
  export type ObservableState<T> = SharedObject & {
14
14
  /**
15
- * The current value. Reads are safe from any thread; prefer writing from a worklet
16
- * so the update runs on the native UI thread. Updating state from the JS thread
17
- * might show a development warning.
15
+ * The current value.
16
+ *
17
+ * Writes from a UI worklet are synchronous and immediately readable. Writes
18
+ * from the JS thread are scheduled to the UI thread asynchronously, the new value is not readable until the update has been
19
+ * applied. Prefer writing from a worklet when you need synchronous updates
18
20
  */
19
21
  value: T;
22
+
23
+ /**
24
+ * A single listener invoked on the native UI runtime whenever the value changes
25
+ * (after iOS `didSet` and Android's setter). Assigning replaces the previous
26
+ * listener; assign `null` to clear. The initial value does not fire `onChange`.
27
+ *
28
+ * The callback must be a worklet so it can run synchronously on the UI thread.
29
+ * Attach it inside `useEffect` and clear it in the cleanup so the listener
30
+ * lifecycle matches the component lifecycle.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * const state = useNativeState(0);
35
+ *
36
+ * useEffect(() => {
37
+ * state.onChange = (value) => {
38
+ * 'worklet';
39
+ * console.log('changed to', value);
40
+ * };
41
+ * return () => {
42
+ * state.onChange = null;
43
+ * };
44
+ * }, []);
45
+ * ```
46
+ */
47
+ onChange: { listener(value: T): void }['listener'] | null;
20
48
  };
21
49
 
22
50
  /**
@@ -28,6 +56,7 @@ export function useNativeState<T>(initialValue: T): ObservableState<T> {
28
56
  return useReleasingSharedObject(() => {
29
57
  const state = new ExpoUI.ObservableState({ value: initialValueRef.current });
30
58
  defineValueProperty(state);
59
+ defineOnChangeProperty(state);
31
60
  return state;
32
61
  }, []) as ObservableState<T>;
33
62
  }
@@ -35,26 +64,57 @@ export function useNativeState<T>(initialValue: T): ObservableState<T> {
35
64
  type NativeObservableState = {
36
65
  getValue(): unknown;
37
66
  setValue(v: { value: unknown }): void;
67
+ setOnChange(callback: object | null): void;
38
68
  };
39
69
 
40
70
  /**
41
71
  * Adds a `value` property that delegates to the native `getValue`/`setValue` functions.
42
72
  */
43
73
  function defineValueProperty(state: NativeObservableState): void {
44
- let warnedOnJSWrite = false;
45
74
  Object.defineProperty(state, 'value', {
46
75
  get() {
47
76
  return state.getValue();
48
77
  },
49
78
  set(v: unknown) {
50
- if (__DEV__ && !warnedOnJSWrite && worklets && !worklets.isUIRuntime()) {
51
- warnedOnJSWrite = true;
52
- console.warn(
53
- 'ObservableState.value was set from the JS thread, the result may be unexpected. ' +
54
- 'Use a worklet to update the state.'
79
+ state.setValue({ value: v });
80
+ },
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Adds an `onChange` property that wraps the user's worklet function as a
86
+ * `WorkletCallback` SharedObject before handing it to native. The cached
87
+ * function (not the SharedObject) is what the getter returns, so reading
88
+ * `state.onChange` gives back what the user assigned.
89
+ */
90
+ function defineOnChangeProperty(state: NativeObservableState): void {
91
+ let currentFn: ((value: unknown) => void) | null = null;
92
+ Object.defineProperty(state, 'onChange', {
93
+ get() {
94
+ return currentFn;
95
+ },
96
+ set(fn: ((value: unknown) => void) | null | undefined) {
97
+ if (!fn) {
98
+ currentFn = null;
99
+ state.setOnChange(null);
100
+ return;
101
+ }
102
+ if (!worklets) {
103
+ throw new Error(
104
+ "ObservableState.onChange requires the 'react-native-worklets' package, which couldn't be loaded. " +
105
+ 'Install react-native-worklets and rebuild the native app, then assign onChange again.'
55
106
  );
56
107
  }
57
- state.setValue({ value: v });
108
+ if (!worklets.isWorkletFunction(fn)) {
109
+ throw new Error(
110
+ 'ObservableState.onChange must be a worklet so it can run on the UI runtime when the native value changes. ' +
111
+ "Add the 'worklet' directive as the first statement in your callback: " +
112
+ "state.onChange = (value) => { 'worklet'; ... };"
113
+ );
114
+ }
115
+ currentFn = fn;
116
+ const callback = new ExpoUI.WorkletCallback(worklets.createSerializable(fn));
117
+ state.setOnChange(callback);
58
118
  },
59
119
  });
60
120
  }
@@ -84,12 +84,6 @@ export function BottomSheet(props: BottomSheetProps) {
84
84
  } = props;
85
85
  const { width } = useWindowDimensions();
86
86
 
87
- // Two-state pattern for animated close:
88
- // - isMounted: whether the native sheet tree exists in the React tree
89
- // - isPresented: passed to native isPresented prop (controls SwiftUI animation)
90
- // On close: isPresented→false (native animates out) → onIsPresentedChange fires → isMounted→false (unmount)
91
- // On open: isMounted→true + isPresented→true (mount + native animates in)
92
- const [isMounted, setIsMounted] = useState(indexProp >= 0);
93
87
  const [isPresented, setIsPresented] = useState(indexProp >= 0);
94
88
  const [currentIndex, setCurrentIndex] = useState(Math.max(indexProp, 0));
95
89
  // Ref mirrors currentIndex for use in handleDetentChange without adding it as a useCallback dep
@@ -129,7 +123,6 @@ export function BottomSheet(props: BottomSheetProps) {
129
123
  fireCloseCallbacks();
130
124
  } else if (indexProp >= 0) {
131
125
  closedRef.current = false;
132
- setIsMounted(true);
133
126
  setIsPresented(true);
134
127
  const clampedIndex = Math.min(indexProp, detents.length - 1);
135
128
  setCurrentIndex(clampedIndex);
@@ -141,7 +134,6 @@ export function BottomSheet(props: BottomSheetProps) {
141
134
  (presented: boolean) => {
142
135
  if (!presented) {
143
136
  setIsPresented(false);
144
- setIsMounted(false);
145
137
  fireCloseCallbacks();
146
138
  }
147
139
  },
@@ -169,7 +161,6 @@ export function BottomSheet(props: BottomSheetProps) {
169
161
  }
170
162
  const clampedIndex = Math.min(Math.max(index, 0), detents.length - 1);
171
163
  closedRef.current = false;
172
- setIsMounted(true);
173
164
  setIsPresented(true);
174
165
  currentIndexRef.current = clampedIndex;
175
166
  setCurrentIndex(clampedIndex);
@@ -224,14 +215,6 @@ export function BottomSheet(props: BottomSheetProps) {
224
215
  ]
225
216
  );
226
217
 
227
- if (!isMounted) {
228
- return (
229
- <BottomSheetInternalContext.Provider value={internalContextValue}>
230
- <BottomSheetContext.Provider value={methods}>{null}</BottomSheetContext.Provider>
231
- </BottomSheetInternalContext.Provider>
232
- );
233
- }
234
-
235
218
  return (
236
219
  <BottomSheetInternalContext.Provider value={internalContextValue}>
237
220
  <BottomSheetContext.Provider value={methods}>
@@ -0,0 +1,224 @@
1
+ import * as React from 'react';
2
+ import { Pressable, View } from 'react-native';
3
+
4
+ import type { MenuAction, MenuComponentProps, MenuComponentRef, NativeActionEvent } from './types';
5
+ import { HorizontalDivider } from '../../jetpack-compose/Divider';
6
+ import { DropdownMenu } from '../../jetpack-compose/DropdownMenu';
7
+ import {
8
+ DropdownMenuItem,
9
+ type DropdownMenuItemElementColors,
10
+ } from '../../jetpack-compose/DropdownMenu/DropdownMenuItem';
11
+ import { Host } from '../../jetpack-compose/Host';
12
+ import { Icon } from '../../jetpack-compose/Icon';
13
+ import { RNHostView } from '../../jetpack-compose/RNHostView';
14
+ import { Text as ComposeText } from '../../jetpack-compose/Text';
15
+ import { useMaterialColors } from '../../jetpack-compose/colors';
16
+
17
+ function actionId(action: MenuAction): string {
18
+ return action.id ?? action.title;
19
+ }
20
+
21
+ function makeEvent(action: MenuAction): NativeActionEvent {
22
+ return { nativeEvent: { event: actionId(action) } };
23
+ }
24
+
25
+ function buildElementColors(
26
+ action: MenuAction,
27
+ destructiveColor: string
28
+ ): DropdownMenuItemElementColors | undefined {
29
+ const isDestructive = action.attributes?.destructive === true;
30
+ const textColor = action.titleColor ?? (isDestructive ? destructiveColor : undefined);
31
+ // The leading icon picks up `leadingIconColor` via `LocalContentColor`, but only
32
+ // when the `Icon` itself doesn't set `tint` — so an explicit `imageColor` from
33
+ // the caller still wins.
34
+ const leadingIconColor = isDestructive ? destructiveColor : undefined;
35
+ if (textColor == null && leadingIconColor == null) {
36
+ return undefined;
37
+ }
38
+ return {
39
+ textColor,
40
+ disabledTextColor: textColor,
41
+ leadingIconColor,
42
+ disabledLeadingIconColor: leadingIconColor,
43
+ };
44
+ }
45
+
46
+ type ItemProps = {
47
+ action: MenuAction;
48
+ onPressAction: MenuComponentProps['onPressAction'];
49
+ dismissAll: () => void;
50
+ destructiveColor: string;
51
+ };
52
+
53
+ function MenuActionItem({ action, onPressAction, dismissAll, destructiveColor }: ItemProps) {
54
+ const [submenuExpanded, setSubmenuExpanded] = React.useState(false);
55
+
56
+ if (action.attributes?.hidden) {
57
+ return null;
58
+ }
59
+
60
+ const { subactions, displayInline, state, attributes, title, image, imageColor } = action;
61
+ // `image` is non-string only when caller passes an ImageSourcePropType
62
+ // (number from `require()` or `{ uri }`). The string form is iOS-only (SF Symbol).
63
+ const leadingIconSource = typeof image === 'string' || image == null ? null : image;
64
+ const elementColors = buildElementColors(action, destructiveColor);
65
+
66
+ if (subactions && subactions.length > 0) {
67
+ if (displayInline) {
68
+ return (
69
+ <>
70
+ <HorizontalDivider />
71
+ {subactions.map((sub) => (
72
+ <MenuActionItem
73
+ key={actionId(sub)}
74
+ action={sub}
75
+ onPressAction={onPressAction}
76
+ dismissAll={dismissAll}
77
+ destructiveColor={destructiveColor}
78
+ />
79
+ ))}
80
+ <HorizontalDivider />
81
+ </>
82
+ );
83
+ }
84
+ return (
85
+ <DropdownMenu expanded={submenuExpanded} onDismissRequest={() => setSubmenuExpanded(false)}>
86
+ <DropdownMenu.Trigger>
87
+ <DropdownMenuItem
88
+ enabled={!attributes?.disabled}
89
+ elementColors={elementColors}
90
+ onClick={() => setSubmenuExpanded(true)}>
91
+ <DropdownMenuItem.Text>
92
+ <ComposeText>{title}</ComposeText>
93
+ </DropdownMenuItem.Text>
94
+ {leadingIconSource && (
95
+ <DropdownMenuItem.LeadingIcon>
96
+ <Icon source={leadingIconSource} size={24} tint={imageColor} />
97
+ </DropdownMenuItem.LeadingIcon>
98
+ )}
99
+ </DropdownMenuItem>
100
+ </DropdownMenu.Trigger>
101
+ <DropdownMenu.Items>
102
+ {subactions.map((sub) => (
103
+ <MenuActionItem
104
+ key={actionId(sub)}
105
+ action={sub}
106
+ onPressAction={onPressAction}
107
+ dismissAll={() => {
108
+ setSubmenuExpanded(false);
109
+ dismissAll();
110
+ }}
111
+ destructiveColor={destructiveColor}
112
+ />
113
+ ))}
114
+ </DropdownMenu.Items>
115
+ </DropdownMenu>
116
+ );
117
+ }
118
+
119
+ return (
120
+ <DropdownMenuItem
121
+ enabled={!attributes?.disabled}
122
+ elementColors={elementColors}
123
+ onClick={() => {
124
+ onPressAction?.(makeEvent(action));
125
+ dismissAll();
126
+ }}>
127
+ <DropdownMenuItem.Text>
128
+ <ComposeText>{title}</ComposeText>
129
+ </DropdownMenuItem.Text>
130
+ {leadingIconSource && (
131
+ <DropdownMenuItem.LeadingIcon>
132
+ <Icon source={leadingIconSource} size={24} tint={imageColor} />
133
+ </DropdownMenuItem.LeadingIcon>
134
+ )}
135
+ {state === 'on' && (
136
+ <DropdownMenuItem.TrailingIcon>
137
+ <ComposeText>✓</ComposeText>
138
+ </DropdownMenuItem.TrailingIcon>
139
+ )}
140
+ </DropdownMenuItem>
141
+ );
142
+ }
143
+
144
+ /**
145
+ * A drop-in replacement for `@react-native-menu/menu` on Android.
146
+ * Wraps the trigger in a `Pressable` (whose `onPress`/`onLongPress` opens the menu) and
147
+ * renders the actions tree as a controlled Material `DropdownMenu`.
148
+ *
149
+ * Note: when `action.image` is a string, it is treated as an iOS SF Symbol and ignored
150
+ * on Android — pass an `ImageSourcePropType` (e.g. `require('./icon.xml')`) to render
151
+ * a leading icon. `MenuView.title` is also unused on Android since Material
152
+ * `DropdownMenu` has no title slot.
153
+ */
154
+ export function MenuView(props: MenuComponentProps & { ref?: React.Ref<MenuComponentRef> }) {
155
+ const {
156
+ ref,
157
+ actions,
158
+ onPressAction,
159
+ onOpenMenu,
160
+ onCloseMenu,
161
+ shouldOpenOnLongPress,
162
+ style,
163
+ children,
164
+ testID,
165
+ } = props;
166
+ const [expanded, setExpanded] = React.useState(false);
167
+ // Mirror `expanded` into a ref and flip it eagerly inside the callbacks so a
168
+ // second call within the same React tick is a no-op (the state update is
169
+ // async and wouldn't otherwise reflect back to the ref in time).
170
+ const expandedRef = React.useRef(false);
171
+
172
+ const open = React.useCallback(() => {
173
+ if (expandedRef.current) return;
174
+ expandedRef.current = true;
175
+ setExpanded(true);
176
+ onOpenMenu?.();
177
+ }, [onOpenMenu]);
178
+
179
+ const dismissAll = React.useCallback(() => {
180
+ if (!expandedRef.current) return;
181
+ expandedRef.current = false;
182
+ setExpanded(false);
183
+ onCloseMenu?.();
184
+ }, [onCloseMenu]);
185
+
186
+ React.useImperativeHandle(ref, () => ({ show: open }), [open]);
187
+
188
+ const destructiveColor = useMaterialColors().error;
189
+
190
+ return (
191
+ <View style={style} testID={testID}>
192
+ <Host matchContents>
193
+ <DropdownMenu expanded={expanded} onDismissRequest={dismissAll}>
194
+ <DropdownMenu.Trigger>
195
+ <RNHostView matchContents>
196
+ <Pressable
197
+ onPress={shouldOpenOnLongPress ? undefined : open}
198
+ onLongPress={shouldOpenOnLongPress ? open : undefined}
199
+ // Mirror upstream `@react-native-menu/menu`, which intercepts touches
200
+ // natively on a bare `ReactViewGroup`: no click sound, no focus
201
+ // highlight, no extra a11y node — children declare their own role.
202
+ android_disableSound
203
+ focusable={false}
204
+ accessible={false}>
205
+ {children}
206
+ </Pressable>
207
+ </RNHostView>
208
+ </DropdownMenu.Trigger>
209
+ <DropdownMenu.Items>
210
+ {actions.map((action) => (
211
+ <MenuActionItem
212
+ key={actionId(action)}
213
+ action={action}
214
+ onPressAction={onPressAction}
215
+ dismissAll={dismissAll}
216
+ destructiveColor={destructiveColor}
217
+ />
218
+ ))}
219
+ </DropdownMenu.Items>
220
+ </DropdownMenu>
221
+ </Host>
222
+ </View>
223
+ );
224
+ }