@expo/ui 58.0.11 → 58.0.13

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 (88) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/DatePickerView.kt +1 -0
  4. package/build/State/index.d.ts +1 -0
  5. package/build/State/index.js +1 -0
  6. package/build/State/index.js.map +1 -1
  7. package/build/State/useWorkletCallback.d.ts +31 -0
  8. package/build/State/useWorkletCallback.js +30 -0
  9. package/build/State/useWorkletCallback.js.map +1 -0
  10. package/build/jetpack-compose/index.d.ts +1 -1
  11. package/build/jetpack-compose/index.js +1 -1
  12. package/build/jetpack-compose/index.js.map +1 -1
  13. package/build/swift-ui/ArrangementView/index.d.ts +48 -0
  14. package/build/swift-ui/ArrangementView/index.js +56 -0
  15. package/build/swift-ui/ArrangementView/index.js.map +1 -0
  16. package/build/swift-ui/index.d.ts +2 -1
  17. package/build/swift-ui/index.js +2 -1
  18. package/build/swift-ui/index.js.map +1 -1
  19. package/build/swift-ui/modifiers/animation/index.d.ts +6 -1
  20. package/build/swift-ui/modifiers/animation/index.js +24 -14
  21. package/build/swift-ui/modifiers/animation/index.js.map +1 -1
  22. package/build/swift-ui/modifiers/animation/types.d.ts +15 -1
  23. package/build/swift-ui/modifiers/animation/types.js.map +1 -1
  24. package/build/swift-ui/modifiers/arrangementModifiers.d.ts +109 -0
  25. package/build/swift-ui/modifiers/arrangementModifiers.js +35 -0
  26. package/build/swift-ui/modifiers/arrangementModifiers.js.map +1 -0
  27. package/build/swift-ui/modifiers/hingeObservation.d.ts +73 -0
  28. package/build/swift-ui/modifiers/hingeObservation.js +45 -0
  29. package/build/swift-ui/modifiers/hingeObservation.js.map +1 -0
  30. package/build/swift-ui/modifiers/index.d.ts +34 -2
  31. package/build/swift-ui/modifiers/index.js +20 -0
  32. package/build/swift-ui/modifiers/index.js.map +1 -1
  33. package/ios/ArrangementViewView.swift +40 -0
  34. package/ios/ExpoUIModule.swift +1 -0
  35. package/ios/Modifiers/AnimationConfig.swift +20 -0
  36. package/ios/Modifiers/ArrangementModifiers.swift +157 -0
  37. package/ios/Modifiers/HingeObservationModifiers.swift +82 -0
  38. package/ios/Modifiers/ViewModifierRegistry.swift +109 -0
  39. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.11/expo.modules.ui-58.0.11-sources.jar → 58.0.13/expo.modules.ui-58.0.13-sources.jar} +0 -0
  40. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13-sources.jar.md5 +1 -0
  41. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13-sources.jar.sha1 +1 -0
  42. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13-sources.jar.sha256 +1 -0
  43. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13-sources.jar.sha512 +1 -0
  44. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar +0 -0
  45. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar.md5 +1 -0
  46. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar.sha1 +1 -0
  47. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar.sha256 +1 -0
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar.sha512 +1 -0
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.11/expo.modules.ui-58.0.11.module → 58.0.13/expo.modules.ui-58.0.13.module} +22 -22
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.module.md5 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.module.sha1 +1 -0
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.module.sha256 +1 -0
  53. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.module.sha512 +1 -0
  54. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.11/expo.modules.ui-58.0.11.pom → 58.0.13/expo.modules.ui-58.0.13.pom} +1 -1
  55. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.pom.md5 +1 -0
  56. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.pom.sha1 +1 -0
  57. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.pom.sha256 +1 -0
  58. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.pom.sha512 +1 -0
  59. package/package.json +3 -3
  60. package/prebuilds/output/debug/xcframeworks/ExpoUI.tar.gz +0 -0
  61. package/prebuilds/output/release/xcframeworks/ExpoUI.tar.gz +0 -0
  62. package/src/State/index.ts +1 -0
  63. package/src/State/useWorkletCallback.ts +48 -0
  64. package/src/jetpack-compose/index.ts +1 -1
  65. package/src/swift-ui/ArrangementView/index.tsx +70 -0
  66. package/src/swift-ui/index.tsx +2 -1
  67. package/src/swift-ui/modifiers/animation/index.ts +24 -11
  68. package/src/swift-ui/modifiers/animation/types.ts +18 -0
  69. package/src/swift-ui/modifiers/arrangementModifiers.ts +142 -0
  70. package/src/swift-ui/modifiers/hingeObservation.ts +91 -0
  71. package/src/swift-ui/modifiers/index.ts +43 -1
  72. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11-sources.jar.md5 +0 -1
  73. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11-sources.jar.sha1 +0 -1
  74. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11-sources.jar.sha256 +0 -1
  75. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11-sources.jar.sha512 +0 -1
  76. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar +0 -0
  77. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar.md5 +0 -1
  78. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar.sha1 +0 -1
  79. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar.sha256 +0 -1
  80. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.aar.sha512 +0 -1
  81. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.module.md5 +0 -1
  82. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.module.sha1 +0 -1
  83. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.module.sha256 +0 -1
  84. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.module.sha512 +0 -1
  85. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.pom.md5 +0 -1
  86. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.pom.sha1 +0 -1
  87. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.pom.sha256 +0 -1
  88. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.11/expo.modules.ui-58.0.11.pom.sha512 +0 -1
@@ -0,0 +1,82 @@
1
+ // Copyright 2026-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+ import SwiftUI
5
+
6
+ internal struct OnHingeChangeModifier: ViewModifier, Record {
7
+ // Worklet path: synchronous invocation on the UI runtime (no JS-thread dispatch).
8
+ @Field var workletCallback: WorkletCallback?
9
+ // JS-thread path: async event via the global modifier event dispatcher.
10
+ var eventDispatcher: EventDispatcher?
11
+ @State private var delivery = HingeDeliveryState()
12
+
13
+ init() {}
14
+
15
+ init(from params: Dict, appContext: AppContext, eventDispatcher: EventDispatcher) throws {
16
+ try self = .init(from: params, appContext: appContext)
17
+ self.eventDispatcher = eventDispatcher
18
+ }
19
+
20
+ func body(content: Content) -> some View {
21
+ #if canImport(SwiftUI, _version: 8.0.85) // iOS 27.1 SDK
22
+ if #available(iOS 27.1, macOS 27.1, tvOS 27.1, visionOS 27.1, *) {
23
+ content.onHingeChange { [workletCallback, eventDispatcher, delivery] oldContext, newContext in
24
+ // SwiftUI repeats the action with equal contexts while a fold relayouts the hierarchy. The
25
+ // first call carries the initial state and passes even when neither context has a hinge.
26
+ guard !delivery.hasDelivered || oldContext != newContext else {
27
+ return
28
+ }
29
+ delivery.hasDelivered = true
30
+ let old = HingeContextPayload(oldContext).dictionary
31
+ let new = HingeContextPayload(newContext).dictionary
32
+ if let workletCallback {
33
+ workletCallback.invoke(arguments: [old, new])
34
+ } else {
35
+ eventDispatcher?(["onHingeChange": ["oldContext": old, "newContext": new]])
36
+ }
37
+ }
38
+ } else {
39
+ content
40
+ }
41
+ #else
42
+ content
43
+ #endif
44
+ }
45
+ }
46
+
47
+ /// Whether the modifier has forwarded its first call, which no later equal-context call repeats.
48
+ private final class HingeDeliveryState {
49
+ var hasDelivered = false
50
+ }
51
+
52
+ /// The hinge context as sent to JS: `hinge` is `null` when the device has no hinge or the view
53
+ /// hierarchy provides no hinge updates. The angle is in degrees.
54
+ internal struct HingeContextPayload {
55
+ let angle: Double?
56
+ let status: String?
57
+
58
+ var dictionary: [String: Any] {
59
+ guard let angle, let status else {
60
+ return ["hinge": NSNull()]
61
+ }
62
+ return ["hinge": ["angle": angle, "status": status]]
63
+ }
64
+ }
65
+
66
+ #if canImport(SwiftUI, _version: 8.0.85) // iOS 27.1 SDK
67
+ @available(iOS 27.1, macOS 27.1, tvOS 27.1, visionOS 27.1, *)
68
+ extension HingeContextPayload {
69
+ init(_ context: DeviceHingeContext) {
70
+ self.init(angle: context.hinge?.angle.degrees, status: context.hinge.map { Self.statusString($0.status) })
71
+ }
72
+
73
+ private static func statusString(_ status: DeviceHinge.Status) -> String {
74
+ return switch status {
75
+ case .closed: "closed"
76
+ case .partiallyOpen: "partiallyOpen"
77
+ case .fullyOpen: "fullyOpen"
78
+ default: "unknown"
79
+ }
80
+ }
81
+ }
82
+ #endif
@@ -1819,6 +1819,83 @@ internal struct NavigationTitleModifier: ViewModifier, Record {
1819
1819
  }
1820
1820
  }
1821
1821
 
1822
+ internal enum NavigationBarTitleDisplayMode: String, Enumerable {
1823
+ case automatic
1824
+ case inline
1825
+ case large
1826
+
1827
+ #if os(iOS)
1828
+ var value: NavigationBarItem.TitleDisplayMode {
1829
+ switch self {
1830
+ case .automatic:
1831
+ return .automatic
1832
+ case .inline:
1833
+ return .inline
1834
+ case .large:
1835
+ return .large
1836
+ }
1837
+ }
1838
+ #endif
1839
+ }
1840
+
1841
+ internal struct NavigationBarTitleDisplayModeModifier: ViewModifier, Record {
1842
+ @Field var displayMode: NavigationBarTitleDisplayMode = .automatic
1843
+
1844
+ func body(content: Content) -> some View {
1845
+ #if os(iOS)
1846
+ content.navigationBarTitleDisplayMode(displayMode.value)
1847
+ #else
1848
+ content
1849
+ #endif
1850
+ }
1851
+ }
1852
+
1853
+ internal enum ToolbarTitleDisplayModeType: String, Enumerable {
1854
+ case automatic
1855
+ case inline
1856
+ case inlineLarge
1857
+ case large
1858
+
1859
+ @available(iOS 17.0, tvOS 17.0, macOS 14.0, *)
1860
+ var value: SwiftUI.ToolbarTitleDisplayMode? {
1861
+ switch self {
1862
+ case .automatic:
1863
+ return .automatic
1864
+ case .inline:
1865
+ return .inline
1866
+ case .inlineLarge:
1867
+ #if os(tvOS)
1868
+ return nil
1869
+ #else
1870
+ return .inlineLarge
1871
+ #endif
1872
+ case .large:
1873
+ #if os(iOS)
1874
+ return .large
1875
+ #else
1876
+ return nil
1877
+ #endif
1878
+ }
1879
+ }
1880
+ }
1881
+
1882
+ internal struct ToolbarTitleDisplayModeModifier: ViewModifier, Record {
1883
+ @Field var mode: ToolbarTitleDisplayModeType = .automatic
1884
+
1885
+ @ViewBuilder
1886
+ func body(content: Content) -> some View {
1887
+ if #available(iOS 17.0, tvOS 17.0, macOS 14.0, *) {
1888
+ if let value = mode.value {
1889
+ content.toolbarTitleDisplayMode(value)
1890
+ } else {
1891
+ content
1892
+ }
1893
+ } else {
1894
+ content
1895
+ }
1896
+ }
1897
+ }
1898
+
1822
1899
  // MARK: - Built-in Modifier Registration
1823
1900
 
1824
1901
  // swiftlint:disable:next no_grouping_extension
@@ -1995,6 +2072,14 @@ extension ViewModifierRegistry {
1995
2072
  return try NavigationTitleModifier(from: params, appContext: appContext)
1996
2073
  }
1997
2074
 
2075
+ register("navigationBarTitleDisplayMode") { params, appContext, _ in
2076
+ return try NavigationBarTitleDisplayModeModifier(from: params, appContext: appContext)
2077
+ }
2078
+
2079
+ register("toolbarTitleDisplayMode") { params, appContext, _ in
2080
+ return try ToolbarTitleDisplayModeModifier(from: params, appContext: appContext)
2081
+ }
2082
+
1998
2083
  register("navigationSplitViewStyle") { params, appContext, _ in
1999
2084
  return try NavigationSplitViewStyleModifier(from: params, appContext: appContext)
2000
2085
  }
@@ -2003,6 +2088,26 @@ extension ViewModifierRegistry {
2003
2088
  return try NavigationSplitViewColumnWidthModifier(from: params, appContext: appContext)
2004
2089
  }
2005
2090
 
2091
+ register("arrangementViewStyle") { params, appContext, _ in
2092
+ return try ArrangementViewStyleModifier(from: params, appContext: appContext)
2093
+ }
2094
+
2095
+ register("splitArrangementLayoutRatio") { params, appContext, _ in
2096
+ return try SplitArrangementLayoutRatioModifier(from: params, appContext: appContext)
2097
+ }
2098
+
2099
+ register("splitArrangementLayoutSize") { params, appContext, _ in
2100
+ return try SplitArrangementLayoutSizeModifier(from: params, appContext: appContext)
2101
+ }
2102
+
2103
+ register("splitArrangementFixedLayoutSize") { params, appContext, _ in
2104
+ return try SplitArrangementFixedLayoutSizeModifier(from: params, appContext: appContext)
2105
+ }
2106
+
2107
+ register("overlayArrangementEdge") { params, appContext, _ in
2108
+ return try OverlayArrangementEdgeModifier(from: params, appContext: appContext)
2109
+ }
2110
+
2006
2111
  register("accessibilityLabel") { params, appContext, _ in
2007
2112
  return try AccessibilityLabelModifier(from: params, appContext: appContext)
2008
2113
  }
@@ -2430,5 +2535,9 @@ extension ViewModifierRegistry {
2430
2535
  register("onScrollGeometryChange") { params, appContext, eventDispatcher in
2431
2536
  return try OnScrollGeometryChangeModifier(from: params, appContext: appContext, eventDispatcher: eventDispatcher)
2432
2537
  }
2538
+
2539
+ register("onHingeChange") { params, appContext, eventDispatcher in
2540
+ return try OnHingeChangeModifier(from: params, appContext: appContext, eventDispatcher: eventDispatcher)
2541
+ }
2433
2542
  }
2434
2543
  }
@@ -0,0 +1 @@
1
+ eee15e7c9f3aeb7b3941ead7ce0e72d8174b0b95964c69ef5a1d5fbf02536fbe
@@ -0,0 +1 @@
1
+ 3e6c99d1b6aa74d01d30339d222653a631dae2abf99075e4c25fc171fbb33f9d55bca7daee4d1cd4c6ecdcdc89fb71067de948ac4a91135b6ce38cbb337c52d1
@@ -0,0 +1 @@
1
+ 1409db74c61bae87d4830fa0652a822c1ba21d80
@@ -0,0 +1 @@
1
+ dc0a8e5a28e1f4f7d722e8706b5858844aa6eac089e89e5f8099374b309bed60
@@ -0,0 +1 @@
1
+ ef66aaa30d2d2703c4ff5c36c117ffaf8dd41a2d2a9a8a286224b817f77d20ae2298cd6e0959e1a78ccc3c741cbc286db2e8d5a086b4ed9e11acc6a206207d68
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "expo.modules.ui",
5
5
  "module": "expo.modules.ui",
6
- "version": "58.0.11",
6
+ "version": "58.0.13",
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.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"
27
+ "name": "expo.modules.ui-58.0.13.aar",
28
+ "url": "expo.modules.ui-58.0.13.aar",
29
+ "size": 1843673,
30
+ "sha512": "ef66aaa30d2d2703c4ff5c36c117ffaf8dd41a2d2a9a8a286224b817f77d20ae2298cd6e0959e1a78ccc3c741cbc286db2e8d5a086b4ed9e11acc6a206207d68",
31
+ "sha256": "dc0a8e5a28e1f4f7d722e8706b5858844aa6eac089e89e5f8099374b309bed60",
32
+ "sha1": "1409db74c61bae87d4830fa0652a822c1ba21d80",
33
+ "md5": "26e374a25a5054c68e67a99ea46b3858"
34
34
  }
35
35
  ]
36
36
  },
@@ -141,13 +141,13 @@
141
141
  ],
142
142
  "files": [
143
143
  {
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"
144
+ "name": "expo.modules.ui-58.0.13.aar",
145
+ "url": "expo.modules.ui-58.0.13.aar",
146
+ "size": 1843673,
147
+ "sha512": "ef66aaa30d2d2703c4ff5c36c117ffaf8dd41a2d2a9a8a286224b817f77d20ae2298cd6e0959e1a78ccc3c741cbc286db2e8d5a086b4ed9e11acc6a206207d68",
148
+ "sha256": "dc0a8e5a28e1f4f7d722e8706b5858844aa6eac089e89e5f8099374b309bed60",
149
+ "sha1": "1409db74c61bae87d4830fa0652a822c1ba21d80",
150
+ "md5": "26e374a25a5054c68e67a99ea46b3858"
151
151
  }
152
152
  ]
153
153
  },
@@ -161,13 +161,13 @@
161
161
  },
162
162
  "files": [
163
163
  {
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"
164
+ "name": "expo.modules.ui-58.0.13-sources.jar",
165
+ "url": "expo.modules.ui-58.0.13-sources.jar",
166
+ "size": 110723,
167
+ "sha512": "3e6c99d1b6aa74d01d30339d222653a631dae2abf99075e4c25fc171fbb33f9d55bca7daee4d1cd4c6ecdcdc89fb71067de948ac4a91135b6ce38cbb337c52d1",
168
+ "sha256": "eee15e7c9f3aeb7b3941ead7ce0e72d8174b0b95964c69ef5a1d5fbf02536fbe",
169
+ "sha1": "e587fcde7f1c58c339f95759565034f989a49dcf",
170
+ "md5": "041ed0d6d536bbcf8d08e7a653bea8ef"
171
171
  }
172
172
  ]
173
173
  }
@@ -0,0 +1 @@
1
+ 9733a96d1ff7d223a5f70be6e6dfe7bb8e87a65d
@@ -0,0 +1 @@
1
+ f69ec3f19d8e25695b4285ffd82dc9c7fae64d77138b3650c75c96d785069f25
@@ -0,0 +1 @@
1
+ 62bb4e1488c2d1ec2a92018daf0e9a3743b13f2eac6fd9f2824b2811a50ea67f94d13aa8bda773a19bf65987b34813baeefa2103ea9af839451034086683378e
@@ -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.11</version>
12
+ <version>58.0.13</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
+ 3cd5de5e06cb53c184c41eb8b7136e576bdfae63
@@ -0,0 +1 @@
1
+ 8140b397ebcb1f6d3c375179559510d32fdeeb8b95772cba5bc2119bc5c7e5ed
@@ -0,0 +1 @@
1
+ 877cc4dd09304c8a40de927737422f89e43dbb7893f8d529edbf585b886113ec03bd15df807d3776ff1b22b5214390277f2fdfa2b525eb950968e534bf3a39ad
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/ui",
3
- "version": "58.0.11",
3
+ "version": "58.0.13",
4
4
  "description": "A collection of UI components",
5
5
  "keywords": [
6
6
  "Jetpack Compose",
@@ -145,10 +145,10 @@
145
145
  "@testing-library/react": "^16.3.0",
146
146
  "@testing-library/react-native": "^14.0.1",
147
147
  "@types/babel__core": "^7.20.5",
148
- "@types/jest": "^29.2.1",
148
+ "@types/jest": "^30.0.0",
149
149
  "@types/node": "^22.14.0",
150
150
  "@types/react": "~19.3.0",
151
- "expo-module-scripts": "56.0.5",
151
+ "expo-module-scripts": "56.0.7",
152
152
  "react-native-reanimated": "4.7.0",
153
153
  "react-native-worklets": "0.13.0"
154
154
  },
@@ -6,5 +6,6 @@ import './index.fx';
6
6
 
7
7
  export { useNativeState, type ObservableState } from './useNativeState';
8
8
  export { useWorkletProp } from './useWorkletProp';
9
+ export { useWorkletCallback, type WorkletCallback } from './useWorkletCallback';
9
10
  export { worklets } from './optionalWorklets';
10
11
  export { getStateId } from './utils';
@@ -0,0 +1,48 @@
1
+ import type { SharedObject } from 'expo';
2
+
3
+ import { worklets } from './optionalWorklets';
4
+ import { useWorkletProp } from './useWorkletProp';
5
+
6
+ /**
7
+ * A worklet function wrapped for native code, returned by [`useWorkletCallback`](#useworkletcallback).
8
+ * Pass it to a modifier or prop that accepts worklet callbacks, which then runs it synchronously on
9
+ * the UI thread.
10
+ */
11
+ export type WorkletCallback<T extends (...args: never[]) => void> = SharedObject & {
12
+ /** @hidden */
13
+ readonly __workletCallbackType?: T;
14
+ };
15
+
16
+ /**
17
+ * Wraps a worklet function so native code can run it synchronously on the UI thread, with no
18
+ * JS-thread round trip. Pass the result to a modifier that accepts worklet callbacks, such as
19
+ * `onHingeChange`. The callback must start with the `'worklet'` directive, and
20
+ * [`react-native-worklets`](https://docs.swmansion.com/react-native-worklets/) must be installed.
21
+ *
22
+ * The native callback is updated when `callback` changes and released when the component unmounts,
23
+ * so call it at the top of your component like any hook.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * const angle = useNativeState(180);
28
+ * const onHinge = useWorkletCallback((_, newContext) => {
29
+ * 'worklet';
30
+ * angle.value = newContext.hinge?.angle ?? 180;
31
+ * });
32
+ *
33
+ * <VStack modifiers={[onHingeChange(onHinge)]} />
34
+ * ```
35
+ */
36
+ export function useWorkletCallback<T extends (...args: never[]) => void>(
37
+ callback: T
38
+ ): WorkletCallback<T> {
39
+ const workletCallback = useWorkletProp(callback as unknown as (...args: unknown[]) => void);
40
+ if (!worklets || !workletCallback) {
41
+ throw new Error(
42
+ "useWorkletCallback needs the 'react-native-worklets' package, which couldn't be loaded. " +
43
+ 'Install react-native-worklets and rebuild the native app, or pass a plain function ' +
44
+ 'where the API accepts one.'
45
+ );
46
+ }
47
+ return workletCallback as WorkletCallback<T>;
48
+ }
@@ -72,6 +72,6 @@ export * from './Box';
72
72
  export * from './Row';
73
73
  export * from './Column';
74
74
  export * from './FlowRow';
75
- export { useNativeState } from '../State';
75
+ export { useNativeState, useWorkletCallback, type WorkletCallback } from '../State';
76
76
  export type { ViewEvent } from '../types';
77
77
  export type { PrimitiveBaseProps } from './layout-types';
@@ -0,0 +1,70 @@
1
+ import { requireNativeView } from 'expo';
2
+
3
+ import { Slot } from '../SlotView';
4
+ import { createViewModifierEventListener } from '../modifiers/utils';
5
+ import { type CommonViewModifierProps } from '../types';
6
+
7
+ export interface ArrangementViewProps extends CommonViewModifierProps {
8
+ /**
9
+ * The views to arrange. Provide `ArrangementView.Primary` and `ArrangementView.Secondary`.
10
+ */
11
+ children: React.ReactNode;
12
+ }
13
+
14
+ const ArrangementViewNativeView: React.ComponentType<ArrangementViewProps> = requireNativeView(
15
+ 'ExpoUI',
16
+ 'ArrangementViewView'
17
+ );
18
+
19
+ /**
20
+ * The primary view of the arrangement.
21
+ */
22
+ function ArrangementViewPrimary(props: { children: React.ReactNode }) {
23
+ return <Slot name="primary">{props.children}</Slot>;
24
+ }
25
+
26
+ /**
27
+ * The secondary view of the arrangement.
28
+ */
29
+ function ArrangementViewSecondary(props: { children: React.ReactNode }) {
30
+ return <Slot name="secondary">{props.children}</Slot>;
31
+ }
32
+
33
+ ArrangementView.Primary = ArrangementViewPrimary;
34
+ ArrangementView.Secondary = ArrangementViewSecondary;
35
+
36
+ /**
37
+ * ArrangementView uses the native [ArrangementView](https://developer.apple.com/documentation/swiftui/arrangementview) view.
38
+ *
39
+ * A view that arranges primary and secondary content using an adaptive layout that responds to
40
+ * the environment.
41
+ *
42
+ * > **Note:** Below iOS 27.1, the children render without a container.
43
+ * @example
44
+ * ```tsx
45
+ * <Host style={{ flex: 1 }}>
46
+ * <ArrangementView modifiers={[arrangementViewStyle('split')]}>
47
+ * <ArrangementView.Primary>
48
+ * <NowPlaying />
49
+ * </ArrangementView.Primary>
50
+ * <ArrangementView.Secondary>
51
+ * <Lyrics />
52
+ * </ArrangementView.Secondary>
53
+ * </ArrangementView>
54
+ * </Host>
55
+ * ```
56
+ * @platform ios 27.1+
57
+ * @platform tvos 27.1+
58
+ */
59
+ export function ArrangementView(props: ArrangementViewProps) {
60
+ const { modifiers, children, ...restProps } = props;
61
+
62
+ return (
63
+ <ArrangementViewNativeView
64
+ modifiers={modifiers}
65
+ {...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
66
+ {...restProps}>
67
+ {children}
68
+ </ArrangementViewNativeView>
69
+ );
70
+ }
@@ -29,6 +29,7 @@ export * from './Menu';
29
29
  export * from './NavigationDestination';
30
30
  export * from './NavigationLink';
31
31
  export * from './NavigationSplitView';
32
+ export * from './ArrangementView';
32
33
  export * from './NavigationStack';
33
34
  export * from './Picker';
34
35
  export * from './ProgressView';
@@ -39,7 +40,7 @@ export * from './Spacer';
39
40
  export * from './Stepper';
40
41
  export * from './SwipeActions';
41
42
  export * from './Text';
42
- export { useNativeState } from '../State';
43
+ export { useNativeState, useWorkletCallback, type WorkletCallback } from '../State';
43
44
  export { withAnimation, type WithAnimationCompletionCriteria } from './withAnimation';
44
45
  export * from './SyncToggle';
45
46
  export * from './TabView';
@@ -5,6 +5,7 @@ import type {
5
5
  ChainableAnimationType,
6
6
  InterpolatingSpringAnimationParams,
7
7
  SpringAnimationParams,
8
+ SpringPresetAnimationParams,
8
9
  TimingAnimationParams,
9
10
  } from './types';
10
11
 
@@ -16,6 +17,8 @@ import type {
16
17
  * - `spring` accepts [`SpringAnimationParams`](#springanimationparams).
17
18
  * - `interpolatingSpring` accepts
18
19
  * [`InterpolatingSpringAnimationParams`](#interpolatingspringanimationparams).
20
+ * - Spring presets (`smooth`, `snappy`, `bouncy`) accept
21
+ * [`SpringPresetAnimationParams`](#springpresetanimationparams).
19
22
  * - Chaining returns [`ChainableAnimationType`](#chainableanimationtype).
20
23
  *
21
24
  * @example
@@ -80,23 +83,33 @@ export const Animation = {
80
83
  duration: params?.duration,
81
84
  bounce: params?.bounce,
82
85
  }),
86
+ smooth: (params?: SpringPresetAnimationParams) =>
87
+ ChainableAnimation({
88
+ type: 'smooth',
89
+ duration: params?.duration,
90
+ extraBounce: params?.extraBounce,
91
+ }),
92
+ snappy: (params?: SpringPresetAnimationParams) =>
93
+ ChainableAnimation({
94
+ type: 'snappy',
95
+ duration: params?.duration,
96
+ extraBounce: params?.extraBounce,
97
+ }),
98
+ bouncy: (params?: SpringPresetAnimationParams) =>
99
+ ChainableAnimation({
100
+ type: 'bouncy',
101
+ duration: params?.duration,
102
+ extraBounce: params?.extraBounce,
103
+ }),
83
104
 
84
105
  default: ChainableAnimation({ type: 'default' }),
85
106
  };
86
107
 
87
108
  function ChainableAnimation(animation: AnimationObject): ChainableAnimationType {
88
- let _animation: AnimationObject = animation;
89
-
90
109
  return {
91
- delay: (delay) => {
92
- _animation = { ..._animation, delay };
93
- return ChainableAnimation(_animation);
94
- },
95
- repeat: (params) => {
96
- _animation = { ..._animation, ...params };
97
- return ChainableAnimation(_animation);
98
- },
99
- [VALUE_SYMBOL]: () => _animation,
110
+ delay: (delay) => ChainableAnimation({ ...animation, delay }),
111
+ repeat: (params) => ChainableAnimation({ ...animation, ...params }),
112
+ [VALUE_SYMBOL]: () => animation,
100
113
  };
101
114
  }
102
115
 
@@ -12,6 +12,9 @@ export type AnimationObject = {
12
12
  | 'linear'
13
13
  | 'spring'
14
14
  | 'interpolatingSpring'
15
+ | 'smooth'
16
+ | 'snappy'
17
+ | 'bouncy'
15
18
  | 'default';
16
19
  duration?: number;
17
20
  response?: number;
@@ -22,6 +25,7 @@ export type AnimationObject = {
22
25
  stiffness?: number;
23
26
  damping?: number;
24
27
  initialVelocity?: number;
28
+ extraBounce?: number;
25
29
  delay?: number;
26
30
  repeatCount?: number;
27
31
  autoreverses?: boolean;
@@ -84,6 +88,20 @@ export type InterpolatingSpringAnimationParams = {
84
88
  bounce?: number;
85
89
  };
86
90
 
91
+ export type SpringPresetAnimationParams = {
92
+ /**
93
+ * The perceptual duration, which defines the pace of the spring (in seconds). This is
94
+ * approximately equal to the settling duration, but for very bouncy springs, it is the period of
95
+ * oscillation of the spring.
96
+ */
97
+ duration?: number;
98
+ /**
99
+ * Bounce added to the base bounce of the preset: 0 for `smooth`, 0.15 for `snappy`, and 0.3 for
100
+ * `bouncy`. Keep the total below 1: at 1 and above, the spring oscillates without settling.
101
+ */
102
+ extraBounce?: number;
103
+ };
104
+
87
105
  export type ChainableAnimationType = {
88
106
  /** Adds a delay before the animation starts (in seconds). */
89
107
  delay: (delay: number) => ChainableAnimationType;