@expo/ui 58.0.15 → 58.0.16

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 (100) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +3 -0
  4. package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +2 -2
  5. package/android/src/main/java/expo/modules/ui/RNHostView.kt +95 -0
  6. package/android/src/main/java/expo/modules/ui/menu/DropdownMenu.kt +8 -1
  7. package/android/src/main/java/expo/modules/ui/menu/DropdownMenuRecords.kt +13 -1
  8. package/build/NativeTreeContext.d.ts +10 -0
  9. package/build/NativeTreeContext.js +25 -0
  10. package/build/NativeTreeContext.js.map +1 -0
  11. package/build/community/bottom-sheet/BottomSheet.ios.js +11 -4
  12. package/build/community/bottom-sheet/BottomSheet.ios.js.map +1 -1
  13. package/build/community/menu/MenuView.android.js +6 -0
  14. package/build/community/menu/MenuView.android.js.map +1 -1
  15. package/build/jetpack-compose/DropdownMenu/index.d.ts +8 -1
  16. package/build/jetpack-compose/DropdownMenu/index.js.map +1 -1
  17. package/build/jetpack-compose/Host/index.js +8 -2
  18. package/build/jetpack-compose/Host/index.js.map +1 -1
  19. package/build/jetpack-compose/RNHostView/index.js +5 -1
  20. package/build/jetpack-compose/RNHostView/index.js.map +1 -1
  21. package/build/swift-ui/Chart/index.d.ts +10 -0
  22. package/build/swift-ui/Chart/index.js.map +1 -1
  23. package/build/swift-ui/Host/index.js +8 -2
  24. package/build/swift-ui/Host/index.js.map +1 -1
  25. package/build/swift-ui/RNHostView.js +5 -1
  26. package/build/swift-ui/RNHostView.js.map +1 -1
  27. package/build/swift-ui/modifiers/presentationModifiers.d.ts +17 -1
  28. package/build/swift-ui/modifiers/presentationModifiers.js +4 -2
  29. package/build/swift-ui/modifiers/presentationModifiers.js.map +1 -1
  30. package/build/types.d.ts +27 -0
  31. package/build/types.js +1 -1
  32. package/build/types.js.map +1 -1
  33. package/build/universal/BottomSheet/index.android.js +26 -18
  34. package/build/universal/BottomSheet/index.android.js.map +1 -1
  35. package/build/universal/BottomSheet/index.ios.js +20 -12
  36. package/build/universal/BottomSheet/index.ios.js.map +1 -1
  37. package/ios/ChartView.swift +7 -4
  38. package/ios/DataListForEachView.swift +1 -0
  39. package/ios/GridView.swift +1 -0
  40. package/ios/HostView.swift +27 -4
  41. package/ios/Modifiers/PresentationModifiers.swift +20 -4
  42. package/ios/NamespaceView.swift +1 -0
  43. package/ios/RNHostView.swift +19 -4
  44. package/ios/SlotView.swift +1 -0
  45. package/ios/TabView/TabView.swift +2 -0
  46. package/ios/ToolbarView.swift +2 -1
  47. package/ios/UIBaseView.swift +13 -0
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.15/expo.modules.ui-58.0.15-sources.jar → 58.0.16/expo.modules.ui-58.0.16-sources.jar} +0 -0
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16-sources.jar.md5 +1 -0
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16-sources.jar.sha1 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16-sources.jar.sha256 +1 -0
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16-sources.jar.sha512 +1 -0
  53. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.aar +0 -0
  54. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.aar.md5 +1 -0
  55. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.aar.sha1 +1 -0
  56. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.aar.sha256 +1 -0
  57. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.aar.sha512 +1 -0
  58. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.15/expo.modules.ui-58.0.15.module → 58.0.16/expo.modules.ui-58.0.16.module} +22 -22
  59. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.module.md5 +1 -0
  60. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.module.sha1 +1 -0
  61. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.module.sha256 +1 -0
  62. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.module.sha512 +1 -0
  63. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.15/expo.modules.ui-58.0.15.pom → 58.0.16/expo.modules.ui-58.0.16.pom} +1 -1
  64. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.pom.md5 +1 -0
  65. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.pom.sha1 +1 -0
  66. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.pom.sha256 +1 -0
  67. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.16/expo.modules.ui-58.0.16.pom.sha512 +1 -0
  68. package/package.json +1 -1
  69. package/prebuilds/output/debug/xcframeworks/ExpoUI.tar.gz +0 -0
  70. package/prebuilds/output/release/xcframeworks/ExpoUI.tar.gz +0 -0
  71. package/src/NativeTreeContext.tsx +31 -0
  72. package/src/community/bottom-sheet/BottomSheet.ios.tsx +7 -6
  73. package/src/community/menu/MenuView.android.tsx +12 -2
  74. package/src/jetpack-compose/DropdownMenu/index.tsx +12 -1
  75. package/src/jetpack-compose/Host/index.tsx +6 -2
  76. package/src/jetpack-compose/RNHostView/index.tsx +3 -1
  77. package/src/swift-ui/Chart/index.tsx +10 -0
  78. package/src/swift-ui/Host/index.tsx +6 -2
  79. package/src/swift-ui/RNHostView.tsx +3 -1
  80. package/src/swift-ui/modifiers/presentationModifiers.ts +18 -2
  81. package/src/types.ts +28 -0
  82. package/src/universal/BottomSheet/index.android.tsx +23 -12
  83. package/src/universal/BottomSheet/index.ios.tsx +20 -9
  84. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15-sources.jar.md5 +0 -1
  85. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15-sources.jar.sha1 +0 -1
  86. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15-sources.jar.sha256 +0 -1
  87. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15-sources.jar.sha512 +0 -1
  88. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.aar +0 -0
  89. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.aar.md5 +0 -1
  90. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.aar.sha1 +0 -1
  91. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.aar.sha256 +0 -1
  92. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.aar.sha512 +0 -1
  93. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.module.md5 +0 -1
  94. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.module.sha1 +0 -1
  95. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.module.sha256 +0 -1
  96. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.module.sha512 +0 -1
  97. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.pom.md5 +0 -1
  98. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.pom.sha1 +0 -1
  99. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.pom.sha256 +0 -1
  100. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.15/expo.modules.ui-58.0.15.pom.sha512 +0 -1
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "expo.modules.ui",
5
5
  "module": "expo.modules.ui",
6
- "version": "58.0.15",
6
+ "version": "58.0.16",
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.15.aar",
28
- "url": "expo.modules.ui-58.0.15.aar",
29
- "size": 1847287,
30
- "sha512": "a96d874afa65f7edf884a6b9ea0d01b7d2eb2f1aeb86db4afaaeefa6073f153f29cafe8a1ce8ae9c8c6069cfe8534197add3dba900e350e381598cf3e76e8c79",
31
- "sha256": "85ad13c4695409acef3dad5a8fd8cb6cbd472bcf2ac7d6514b3f0e9fd3b3d590",
32
- "sha1": "019221c48e7c0648984cb5603c4927d391a241cd",
33
- "md5": "620eb66ce22bd9cd4c1e0a0c6c0812f1"
27
+ "name": "expo.modules.ui-58.0.16.aar",
28
+ "url": "expo.modules.ui-58.0.16.aar",
29
+ "size": 1858313,
30
+ "sha512": "9e42c8a718971e6d77015353c6747570385fe0c1d901cf388a50509e00c9ee8581a81ba88d0e83a611b7ec5a6d1dff4280ecf81ed92776d2cf7c26f48c0048c5",
31
+ "sha256": "b8e480f4d8449359c2f5686c3614c9aa82ef98af9b7ce0edd4d839d14de7696f",
32
+ "sha1": "64369f3b1f16363a28412ac36309b53dc2a29752",
33
+ "md5": "812db5879217f7bbe3b44b5ffcb0725a"
34
34
  }
35
35
  ]
36
36
  },
@@ -141,13 +141,13 @@
141
141
  ],
142
142
  "files": [
143
143
  {
144
- "name": "expo.modules.ui-58.0.15.aar",
145
- "url": "expo.modules.ui-58.0.15.aar",
146
- "size": 1847287,
147
- "sha512": "a96d874afa65f7edf884a6b9ea0d01b7d2eb2f1aeb86db4afaaeefa6073f153f29cafe8a1ce8ae9c8c6069cfe8534197add3dba900e350e381598cf3e76e8c79",
148
- "sha256": "85ad13c4695409acef3dad5a8fd8cb6cbd472bcf2ac7d6514b3f0e9fd3b3d590",
149
- "sha1": "019221c48e7c0648984cb5603c4927d391a241cd",
150
- "md5": "620eb66ce22bd9cd4c1e0a0c6c0812f1"
144
+ "name": "expo.modules.ui-58.0.16.aar",
145
+ "url": "expo.modules.ui-58.0.16.aar",
146
+ "size": 1858313,
147
+ "sha512": "9e42c8a718971e6d77015353c6747570385fe0c1d901cf388a50509e00c9ee8581a81ba88d0e83a611b7ec5a6d1dff4280ecf81ed92776d2cf7c26f48c0048c5",
148
+ "sha256": "b8e480f4d8449359c2f5686c3614c9aa82ef98af9b7ce0edd4d839d14de7696f",
149
+ "sha1": "64369f3b1f16363a28412ac36309b53dc2a29752",
150
+ "md5": "812db5879217f7bbe3b44b5ffcb0725a"
151
151
  }
152
152
  ]
153
153
  },
@@ -161,13 +161,13 @@
161
161
  },
162
162
  "files": [
163
163
  {
164
- "name": "expo.modules.ui-58.0.15-sources.jar",
165
- "url": "expo.modules.ui-58.0.15-sources.jar",
166
- "size": 111654,
167
- "sha512": "5569d8f73d7b0d41af8d77ca8cb4e8685384113a45e151b9c6cdad1b660844183067026b2fc16c150ac409a0a097fb4ac78c4f5c31afe56862f306f8daf7c538",
168
- "sha256": "651218fb79e50f51035a06d7e88ef8cd9cd391f8b66edcf46abdc431f0a41cfc",
169
- "sha1": "584c7a2ab4d40b05b4658c93c1a689ce0587dc06",
170
- "md5": "2ea3d659cdac9ba8f6d43d9679a48905"
164
+ "name": "expo.modules.ui-58.0.16-sources.jar",
165
+ "url": "expo.modules.ui-58.0.16-sources.jar",
166
+ "size": 112962,
167
+ "sha512": "79141ef63c1b975a30858d8c1ca7bccde8d14a64d337883063b3c1cbe44f977cc40e0fda89d3076fd84b5e47308e86b3659c71744a4fc3cac2b858a0686f38c6",
168
+ "sha256": "101a40d45fc8e73887c9518fbc88c31e2a700ca6e62d2cc96dd65f72459a9d69",
169
+ "sha1": "aef15fcbe60dff9cbb6491595df9269d819f7065",
170
+ "md5": "6b0b0d2a72178b6d25a038ee47271abb"
171
171
  }
172
172
  ]
173
173
  }
@@ -0,0 +1 @@
1
+ 81f23fddc089c0a466c08356e6c33881fd08d65c
@@ -0,0 +1 @@
1
+ d57d5ce3086debe5c6c7760679de69409aa264c6871d034bac2140af6245f9f4
@@ -0,0 +1 @@
1
+ 44da04bba32c6fbb281c187d7382eabf9cf3cf674dc9f469335345dfe7268e2818a725531749822cd788eb96ce8c56ecb3535f30c757da77fb67630c050de4f3
@@ -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.15</version>
12
+ <version>58.0.16</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
+ de7f94f1b4c3356f8244f8b620146bb9f37c52b8
@@ -0,0 +1 @@
1
+ 2bc1691b86aa0689fbf3bd19f3904aed5b40d206a8a152a03bf27c92eb871f28
@@ -0,0 +1 @@
1
+ 528fce22a7b79c091d7dab483702c8e99ae783b76bd79c6b11e2086d9c59308f28a1b77e9379d8dc81f3ce6b3916f100d8c5c873ac165f75f780262ae8f56264
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/ui",
3
- "version": "58.0.15",
3
+ "version": "58.0.16",
4
4
  "description": "A collection of UI components",
5
5
  "keywords": [
6
6
  "Jetpack Compose",
@@ -0,0 +1,31 @@
1
+ import { createContext, useContext, useEffect } from 'react';
2
+
3
+ /**
4
+ * `true` inside a `Host`, where SwiftUI or Jetpack Compose renders the content. `RNHostView` sets it
5
+ * back to `false`, because its children are React Native views again.
6
+ */
7
+ export const NativeTreeContext = createContext(false);
8
+
9
+ export function useIsInsideNativeTree(): boolean {
10
+ return useContext(NativeTreeContext);
11
+ }
12
+
13
+ let warned = false;
14
+
15
+ /**
16
+ * Warns once in development when a `Host` renders directly inside another `Host`'s native content.
17
+ */
18
+ export function useWarnIfNestedHost(layoutSystem: 'SwiftUI' | 'Jetpack Compose'): void {
19
+ const isNested = useIsInsideNativeTree();
20
+ useEffect(() => {
21
+ if (__DEV__ && isNested && !warned) {
22
+ warned = true;
23
+ console.warn(
24
+ `[@expo/ui] A \`Host\` is rendered directly inside another \`Host\`'s ${layoutSystem} content. ` +
25
+ `${layoutSystem} places it, but React Native can't see where, so its layout and \`measure()\` ` +
26
+ `can be wrong, and a \`Pressable\` inside it can cancel its press. Wrap the nested \`Host\` in ` +
27
+ `\`RNHostView\`, or render its ${layoutSystem} components directly in the outer \`Host\`.`
28
+ );
29
+ }
30
+ }, [isNested, layoutSystem]);
31
+ }
@@ -199,8 +199,9 @@ export function BottomSheet(props: BottomSheetProps) {
199
199
  const bg = extractBackgroundColor(backgroundStyle);
200
200
  return [
201
201
  ...(fitToContents
202
- ? // Makes the iPad sheet size to that content instead of opening near full height.
203
- [presentationSizing('fitted')]
202
+ ? // Fits the sheet height to the content (iPad opens near full height otherwise) and lets
203
+ // the system choose the width.
204
+ [presentationSizing('automatic', { fitted: { horizontal: false, vertical: true } })]
204
205
  : [
205
206
  presentationDetents(detents, {
206
207
  selection: selectedDetent,
@@ -231,16 +232,16 @@ export function BottomSheet(props: BottomSheetProps) {
231
232
  onDismiss={fireCloseCallbacks}
232
233
  fitToContents={fitToContents}>
233
234
  <Group modifiers={modifiers}>
234
- <RNHostView matchContents={fitToContents}>
235
+ <RNHostView matchContents={fitToContents ? { vertical: true } : false}>
235
236
  {/* paddingTop compensates for tighter spacing between native drag indicator and content
236
237
  compared to gorhom's handle. flexGrow:1 + height:0 (flex-basis 0) fills the snap-point
237
238
  height without inheriting the scrollable child's intrinsic content height. With matchContents,
238
- RNHostView lays the hosted view out at its own size, so `width` gives it the sheet width
239
- while its height stays content-sized. */}
239
+ RNHostView takes the width from the sheet, which can be narrower than the window, and
240
+ the height from the content. */}
240
241
  <View
241
242
  style={
242
243
  fitToContents
243
- ? { width, paddingTop: handleComponent !== null ? 16 : 0 }
244
+ ? { paddingTop: handleComponent !== null ? 16 : 0 }
244
245
  : { flexGrow: 1, height: 0, paddingTop: handleComponent !== null ? 16 : 0 }
245
246
  }>
246
247
  <SheetScrollContextReset>{children}</SheetScrollContextReset>
@@ -12,8 +12,12 @@ import { Icon } from '../../jetpack-compose/Icon';
12
12
  import { RNHostView } from '../../jetpack-compose/RNHostView';
13
13
  import { Text as ComposeText } from '../../jetpack-compose/Text';
14
14
  import { useMaterialColors } from '../../jetpack-compose/colors';
15
+ import type { PopupProperties } from '../../types';
15
16
  import type { MenuAction, MenuComponentProps, MenuComponentRef, NativeActionEvent } from './types';
16
17
 
18
+ // Clipped popups drop the status bar offset, so edge-to-edge menus near the bottom detach from the anchor.
19
+ const POPUP_PROPERTIES: PopupProperties = { clippingEnabled: false };
20
+
17
21
  function actionId(action: MenuAction): string {
18
22
  return action.id ?? action.title;
19
23
  }
@@ -82,7 +86,10 @@ function MenuActionItem({ action, onPressAction, dismissAll, destructiveColor }:
82
86
  );
83
87
  }
84
88
  return (
85
- <DropdownMenu expanded={submenuExpanded} onDismissRequest={() => setSubmenuExpanded(false)}>
89
+ <DropdownMenu
90
+ expanded={submenuExpanded}
91
+ onDismissRequest={() => setSubmenuExpanded(false)}
92
+ properties={POPUP_PROPERTIES}>
86
93
  <DropdownMenu.Trigger>
87
94
  <DropdownMenuItem
88
95
  enabled={!attributes?.disabled}
@@ -191,7 +198,10 @@ export function MenuView(props: MenuComponentProps & { ref?: React.Ref<MenuCompo
191
198
  return (
192
199
  <View style={style} testID={testID}>
193
200
  <Host colorScheme={colorScheme} matchContents>
194
- <DropdownMenu expanded={expanded} onDismissRequest={dismissAll}>
201
+ <DropdownMenu
202
+ expanded={expanded}
203
+ onDismissRequest={dismissAll}
204
+ properties={POPUP_PROPERTIES}>
195
205
  <DropdownMenu.Trigger>
196
206
  <RNHostView matchContents>
197
207
  <Pressable
@@ -3,7 +3,7 @@ import type { ReactNode } from 'react';
3
3
  import type { StyleProp, ViewStyle, ColorValue } from 'react-native';
4
4
 
5
5
  import { PresentedContent } from '../../PresentedContentContext';
6
- import type { ModifierConfig } from '../../types';
6
+ import type { ModifierConfig, PopupProperties } from '../../types';
7
7
  import { createViewModifierEventListener } from '../modifiers/utils';
8
8
 
9
9
  const MenuNativeView: React.ComponentType<NativeMenuProps> = requireNativeView(
@@ -59,6 +59,13 @@ export interface DropdownMenuProps {
59
59
  */
60
60
  shadowElevation?: number;
61
61
 
62
+ /**
63
+ * Properties for the popup window of the dropdown menu.
64
+ *
65
+ * @platform android
66
+ */
67
+ properties?: PopupProperties;
68
+
62
69
  /**
63
70
  * Optional styles to apply to the `DropdownMenu`.
64
71
  */
@@ -76,6 +83,7 @@ type NativeMenuProps = {
76
83
  color?: ColorValue;
77
84
  cornerRadius?: number;
78
85
  shadowElevation?: number;
86
+ properties?: PopupProperties;
79
87
  style?: StyleProp<ViewStyle>;
80
88
  modifiers?: ModifierConfig[];
81
89
  children?: ReactNode;
@@ -129,3 +137,6 @@ DropdownMenu.Items = Items;
129
137
 
130
138
  export { DropdownMenu };
131
139
  export { DropdownMenuItem } from './DropdownMenuItem';
140
+
141
+ // Re-exported so the docs generator includes PopupProperties on the DropdownMenu API page.
142
+ export type { PopupProperties };
@@ -9,6 +9,7 @@ import {
9
9
  useColorScheme as useRNColorScheme,
10
10
  } from 'react-native';
11
11
 
12
+ import { NativeTreeContext, useWarnIfNestedHost } from '../../NativeTreeContext';
12
13
  import { TextInputHostProvider, useTextInputHostRef } from '../../keyboard';
13
14
  import { useMergeRefs } from '../../utils/useMergeRefs';
14
15
  import { getMaterialColors, HostPaletteContext } from '../colors';
@@ -93,6 +94,7 @@ export function Host(props: HostProps) {
93
94
  colorScheme,
94
95
  seedColor,
95
96
  ref,
97
+ children,
96
98
  ...restProps
97
99
  } = props;
98
100
  const schemeString = colorScheme === 'light' || colorScheme === 'dark' ? colorScheme : undefined;
@@ -105,6 +107,7 @@ export function Host(props: HostProps) {
105
107
  );
106
108
  const hostRef = useTextInputHostRef();
107
109
  const mergedRef = useMergeRefs(ref, hostRef);
110
+ useWarnIfNestedHost('Jetpack Compose');
108
111
 
109
112
  return (
110
113
  <HostPaletteContext.Provider value={palette}>
@@ -124,8 +127,9 @@ export function Host(props: HostProps) {
124
127
  layoutDirection={
125
128
  layoutDirection ?? (I18nManager.getConstants().isRTL ? 'rightToLeft' : 'leftToRight')
126
129
  }
127
- ref={mergedRef}
128
- />
130
+ ref={mergedRef}>
131
+ <NativeTreeContext.Provider value>{children}</NativeTreeContext.Provider>
132
+ </HostNativeView>
129
133
  </TextInputHostProvider>
130
134
  </HostPaletteContext.Provider>
131
135
  );
@@ -2,6 +2,7 @@ import { requireNativeView } from 'expo';
2
2
  import type { ReactElement, ComponentType } from 'react';
3
3
  import type { LayoutChangeEvent } from 'react-native';
4
4
 
5
+ import { NativeTreeContext } from '../../NativeTreeContext';
5
6
  import { PresentedContentContext, useIsPresentedInOwnWindow } from '../../PresentedContentContext';
6
7
  import type { ModifierConfig } from '../../types';
7
8
  import { resolveMatchContents } from '../../utils/matchContents';
@@ -80,7 +81,8 @@ export function RNHostView(props: RNHostProps) {
80
81
  key={`${nativeProps.matchContentsHorizontal}-${nativeProps.matchContentsVertical}`}>
81
82
  {/* Reset context here so only nearest RNHostView becomes the layout root for its children, and not any other RNHostView above it in the tree. */}
82
83
  <PresentedContentContext.Provider value={false}>
83
- {props.children}
84
+ {/* Hosted children are React Native views again, so a `Host` among them is not nested. */}
85
+ <NativeTreeContext.Provider value={false}>{props.children}</NativeTreeContext.Provider>
84
86
  </PresentedContentContext.Provider>
85
87
  </NativeRNHostView>
86
88
  );
@@ -102,6 +102,16 @@ export type PieChartStyle = {
102
102
  * Space between slices in points.
103
103
  */
104
104
  angularInset?: number;
105
+ /**
106
+ * Corner radius of each slice in points. On a donut, half the ring's thickness gives fully rounded ends.
107
+ * @default 0
108
+ */
109
+ cornerRadius?: number;
110
+ /**
111
+ * Opacity of each slice, from 0 to 1.
112
+ * @default 0.8
113
+ */
114
+ opacity?: number;
105
115
  };
106
116
 
107
117
  /**
@@ -2,6 +2,7 @@ import { requireNativeView } from 'expo';
2
2
  import type { Ref } from 'react';
3
3
  import { I18nManager, type ColorValue, type StyleProp, type ViewStyle } from 'react-native';
4
4
 
5
+ import { NativeTreeContext, useWarnIfNestedHost } from '../../NativeTreeContext';
5
6
  import { TextInputHostProvider, useTextInputHostRef } from '../../keyboard';
6
7
  import { useMergeRefs } from '../../utils/useMergeRefs';
7
8
  import { createViewModifierEventListener } from '../modifiers/utils';
@@ -81,10 +82,12 @@ export function Host(props: HostProps) {
81
82
  layoutDirection,
82
83
  seedColor,
83
84
  ref,
85
+ children,
84
86
  ...restProps
85
87
  } = props;
86
88
  const hostRef = useTextInputHostRef();
87
89
  const mergedRef = useMergeRefs(ref, hostRef);
90
+ useWarnIfNestedHost('SwiftUI');
88
91
 
89
92
  return (
90
93
  <TextInputHostProvider hostRef={hostRef}>
@@ -104,8 +107,9 @@ export function Host(props: HostProps) {
104
107
  ignoreSafeArea={ignoreSafeArea}
105
108
  seedColor={seedColor}
106
109
  {...restProps}
107
- ref={mergedRef}
108
- />
110
+ ref={mergedRef}>
111
+ <NativeTreeContext.Provider value>{children}</NativeTreeContext.Provider>
112
+ </HostNativeView>
109
113
  </TextInputHostProvider>
110
114
  );
111
115
  }
@@ -1,6 +1,7 @@
1
1
  import { requireNativeView } from 'expo';
2
2
  import type { LayoutChangeEvent } from 'react-native';
3
3
 
4
+ import { NativeTreeContext } from '../NativeTreeContext';
4
5
  import { PresentedContentContext, useIsPresentedInOwnWindow } from '../PresentedContentContext';
5
6
  import { resolveMatchContents } from '../utils/matchContents';
6
7
 
@@ -45,7 +46,8 @@ export function RNHostView({ matchContents, ...props }: RNHostViewProps) {
45
46
  key={`${matchContentsHorizontal}-${matchContentsVertical}`}>
46
47
  {/* Reset context here so only nearest RNHostView becomes the layout root for its children, and not any other RNHostView above it in the tree. */}
47
48
  <PresentedContentContext.Provider value={false}>
48
- {props.children}
49
+ {/* Hosted children are React Native views again, so a `Host` among them is not nested. */}
50
+ <NativeTreeContext.Provider value={false}>{props.children}</NativeTreeContext.Provider>
49
51
  </PresentedContentContext.Provider>
50
52
  </RNHostNativeView>
51
53
  );
@@ -130,12 +130,28 @@ export const interactiveDismissDisabled = (isDisabled: boolean = true) =>
130
130
  */
131
131
  export type PresentationSizingType = 'automatic' | 'fitted' | 'form' | 'page';
132
132
 
133
+ /**
134
+ * Options for the `presentationSizing` modifier.
135
+ */
136
+ export type PresentationSizingOptions = {
137
+ /**
138
+ * The axes on which the sheet fits its content. An axis that is not set keeps the size from
139
+ * `sizing`. For example, `{ horizontal: false, vertical: true }` fits the height to the content
140
+ * and lets the system choose the width.
141
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/presentationsizing/fitted(horizontal:vertical:)).
142
+ */
143
+ fitted?: { horizontal?: boolean; vertical?: boolean };
144
+ };
145
+
133
146
  /**
134
147
  * Sets the sizing of a sheet presentation.
135
148
  * @param sizing - The sizing behavior to apply.
149
+ * @param options - Additional sizing options.
136
150
  * @platform ios 18.0+
137
151
  * @platform tvos 18.0+
138
152
  * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/presentationsizing(_:)).
139
153
  */
140
- export const presentationSizing = (sizing: PresentationSizingType) =>
141
- createModifier('presentationSizing', { sizing });
154
+ export const presentationSizing = (
155
+ sizing: PresentationSizingType,
156
+ options?: PresentationSizingOptions
157
+ ) => createModifier('presentationSizing', { sizing, ...options });
package/src/types.ts CHANGED
@@ -50,3 +50,31 @@ export type DialogProperties = {
50
50
  */
51
51
  decorFitsSystemWindows?: boolean;
52
52
  };
53
+
54
+ /**
55
+ * Properties for the popup window, matching `PopupProperties` in Compose.
56
+ */
57
+ export type PopupProperties = {
58
+ /**
59
+ * Whether the popup is focusable. When `true`, the popup receives IME events and key presses,
60
+ * such as the back button.
61
+ * @default true
62
+ */
63
+ focusable?: boolean;
64
+ /**
65
+ * Whether the popup can be dismissed by pressing the back button. Has no effect when `focusable` is `false`.
66
+ * @default true
67
+ */
68
+ dismissOnBackPress?: boolean;
69
+ /**
70
+ * Whether the popup can be dismissed by clicking outside of its bounds.
71
+ * @default true
72
+ */
73
+ dismissOnClickOutside?: boolean;
74
+ /**
75
+ * Whether the popup window is clipped to the screen boundaries. Set to `false` to let it extend
76
+ * beyond them, which positions the popup accurately.
77
+ * @default true
78
+ */
79
+ clippingEnabled?: boolean;
80
+ };
@@ -7,6 +7,7 @@ import {
7
7
  } from '@expo/ui/jetpack-compose/modifiers';
8
8
  import { useEffect, useRef, useState } from 'react';
9
9
 
10
+ import { useIsInsideNativeTree } from '../../NativeTreeContext';
10
11
  import type { BottomSheetProps, SnapPoint } from './types';
11
12
  import { resolveContentPadding } from './utils';
12
13
 
@@ -46,6 +47,7 @@ export function BottomSheet({
46
47
  containerColor,
47
48
  contentColor,
48
49
  }: BottomSheetProps) {
50
+ const isInsideHost = useIsInsideNativeTree();
49
51
  const sheetRef = useRef<ModalBottomSheetRef>(null);
50
52
  const [mount, setMount] = useState(isPresented);
51
53
 
@@ -79,20 +81,29 @@ export function BottomSheet({
79
81
  if (shouldFillMaxHeight(snapPoints)) contentModifiers.push(fillMaxHeight());
80
82
  if (testID) contentModifiers.push(testIDModifier(testID));
81
83
 
84
+ const sheet = (
85
+ <ModalBottomSheet
86
+ ref={sheetRef}
87
+ onDismissRequest={onDismiss}
88
+ showDragHandle={showDragIndicator}
89
+ skipPartiallyExpanded={shouldSkipPartiallyExpanded(snapPoints)}
90
+ properties={{ shouldDismissOnBackPress, shouldDismissOnClickOutside }}
91
+ scrimColor={scrimColor}
92
+ containerColor={containerColor}
93
+ contentColor={contentColor}
94
+ modifiers={modifiers}>
95
+ <Column modifiers={contentModifiers}>{children}</Column>
96
+ </ModalBottomSheet>
97
+ );
98
+
99
+ // Already inside a `Host`, for example nested in another sheet's content: a `Host` of its own
100
+ // would be a `Host` directly inside Compose.
101
+ if (isInsideHost) {
102
+ return sheet;
103
+ }
82
104
  return (
83
105
  <Host style={{ position: 'absolute' }} pointerEvents="none">
84
- <ModalBottomSheet
85
- ref={sheetRef}
86
- onDismissRequest={onDismiss}
87
- showDragHandle={showDragIndicator}
88
- skipPartiallyExpanded={shouldSkipPartiallyExpanded(snapPoints)}
89
- properties={{ shouldDismissOnBackPress, shouldDismissOnClickOutside }}
90
- scrimColor={scrimColor}
91
- containerColor={containerColor}
92
- contentColor={contentColor}
93
- modifiers={modifiers}>
94
- <Column modifiers={contentModifiers}>{children}</Column>
95
- </ModalBottomSheet>
106
+ {sheet}
96
107
  </Host>
97
108
  );
98
109
  }
@@ -9,6 +9,7 @@ import {
9
9
  type PresentationDetent,
10
10
  } from '@expo/ui/swift-ui/modifiers';
11
11
 
12
+ import { useIsInsideNativeTree } from '../../NativeTreeContext';
12
13
  import type { BottomSheetProps, SnapPoint } from './types';
13
14
  import { resolveContentPadding } from './utils';
14
15
 
@@ -29,6 +30,7 @@ export function BottomSheet({
29
30
  contentPadding,
30
31
  containerColor,
31
32
  }: BottomSheetProps) {
33
+ const isInsideHost = useIsInsideNativeTree();
32
34
  const { top, bottom, left, right } = resolveContentPadding(contentPadding, {
33
35
  top: 16,
34
36
  bottom: 0,
@@ -50,17 +52,26 @@ export function BottomSheet({
50
52
  presentationModifiers.push(...modifiers);
51
53
  }
52
54
 
55
+ const sheet = (
56
+ <SwiftUIBottomSheet
57
+ isPresented={isPresented}
58
+ onIsPresentedChange={(presented) => {
59
+ if (!presented) onDismiss();
60
+ }}
61
+ fitToContents={!snapPoints || snapPoints.length === 0}
62
+ testID={testID}>
63
+ <Group modifiers={presentationModifiers}>{children}</Group>
64
+ </SwiftUIBottomSheet>
65
+ );
66
+
67
+ // Already inside a `Host`, for example nested in another sheet's content: a `Host` of its own
68
+ // would be a `Host` directly inside SwiftUI.
69
+ if (isInsideHost) {
70
+ return sheet;
71
+ }
53
72
  return (
54
73
  <Host style={{ position: 'absolute' }} pointerEvents="none">
55
- <SwiftUIBottomSheet
56
- isPresented={isPresented}
57
- onIsPresentedChange={(presented) => {
58
- if (!presented) onDismiss();
59
- }}
60
- fitToContents={!snapPoints || snapPoints.length === 0}
61
- testID={testID}>
62
- <Group modifiers={presentationModifiers}>{children}</Group>
63
- </SwiftUIBottomSheet>
74
+ {sheet}
64
75
  </Host>
65
76
  );
66
77
  }
@@ -1 +0,0 @@
1
- 584c7a2ab4d40b05b4658c93c1a689ce0587dc06
@@ -1 +0,0 @@
1
- 651218fb79e50f51035a06d7e88ef8cd9cd391f8b66edcf46abdc431f0a41cfc
@@ -1 +0,0 @@
1
- 5569d8f73d7b0d41af8d77ca8cb4e8685384113a45e151b9c6cdad1b660844183067026b2fc16c150ac409a0a097fb4ac78c4f5c31afe56862f306f8daf7c538
@@ -1 +0,0 @@
1
- 019221c48e7c0648984cb5603c4927d391a241cd
@@ -1 +0,0 @@
1
- 85ad13c4695409acef3dad5a8fd8cb6cbd472bcf2ac7d6514b3f0e9fd3b3d590
@@ -1 +0,0 @@
1
- a96d874afa65f7edf884a6b9ea0d01b7d2eb2f1aeb86db4afaaeefa6073f153f29cafe8a1ce8ae9c8c6069cfe8534197add3dba900e350e381598cf3e76e8c79
@@ -1 +0,0 @@
1
- 1f0478b4c8bf3bc52458f429fc59e10278b2ac2c
@@ -1 +0,0 @@
1
- baecdb10cef2e99a106a69d8d1755408faeb3f7f7442966d5e3dbcbfe6e26674
@@ -1 +0,0 @@
1
- 85d71daab274f7e80382dda25bb4fb673bb5d058b58b2f8c6e28cf39f4ff349c9809182bfce05a5395311f2ddf0dd31a830372c49445aaca933908c1327c91ca
@@ -1 +0,0 @@
1
- a9a1e9a3be5d9cd7679f76f857b875155c2bb756
@@ -1 +0,0 @@
1
- 64dbcdae5d503a5245fae1cd35a5a4821daa772a7010e1b76b2fc5bc7fbc5b16
@@ -1 +0,0 @@
1
- 074cbafb601c2b44e22ddc7b09f878b4b98ea71a877ff50c93eab6f7d9c8c18d7629b7fb5e044f9f4d61ef7599e06e9ffdb9d312bae0c4e6d8031eefbfaee45f