@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.
- package/CHANGELOG.md +39 -1
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +44 -3
- package/android/src/main/java/expo/modules/ui/HostView.kt +2 -0
- package/android/src/main/java/expo/modules/ui/LoadingView.kt +80 -0
- package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +50 -4
- package/android/src/main/java/expo/modules/ui/RNHostView.kt +8 -3
- package/android/src/main/java/expo/modules/ui/ShadowNodeSyncFlush.kt +28 -0
- package/android/src/main/java/expo/modules/ui/SnackbarView.kt +126 -0
- package/android/src/main/java/expo/modules/ui/state/ObservableState.kt +10 -0
- package/assets/keyboard_arrow_down.xml +10 -0
- package/build/State/useNativeState.d.ts +32 -3
- package/build/State/useNativeState.d.ts.map +1 -1
- package/build/community/bottom-sheet/BottomSheet.ios.d.ts.map +1 -1
- package/build/community/menu/MenuView.android.d.ts +16 -0
- package/build/community/menu/MenuView.android.d.ts.map +1 -0
- package/build/community/menu/MenuView.d.ts +19 -0
- package/build/community/menu/MenuView.d.ts.map +1 -0
- package/build/community/menu/MenuView.ios.d.ts +10 -0
- package/build/community/menu/MenuView.ios.d.ts.map +1 -0
- package/build/community/menu/index.d.ts +5 -0
- package/build/community/menu/index.d.ts.map +1 -0
- package/build/community/menu/types.d.ts +166 -0
- package/build/community/menu/types.d.ts.map +1 -0
- package/build/jetpack-compose/LoadingIndicator/index.d.ts +41 -0
- package/build/jetpack-compose/LoadingIndicator/index.d.ts.map +1 -0
- package/build/jetpack-compose/Snackbar/index.d.ts +94 -0
- package/build/jetpack-compose/Snackbar/index.d.ts.map +1 -0
- package/build/jetpack-compose/index.d.ts +2 -0
- package/build/jetpack-compose/index.d.ts.map +1 -1
- package/build/jetpack-compose/modifiers/index.d.ts +21 -2
- package/build/jetpack-compose/modifiers/index.d.ts.map +1 -1
- package/build/swift-ui/Alert/index.d.ts +42 -0
- package/build/swift-ui/Alert/index.d.ts.map +1 -0
- package/build/swift-ui/BottomSheet/index.d.ts +5 -1
- package/build/swift-ui/BottomSheet/index.d.ts.map +1 -1
- package/build/swift-ui/SlotView.d.ts +5 -2
- package/build/swift-ui/SlotView.d.ts.map +1 -1
- package/build/swift-ui/SwipeActions/index.d.ts +38 -0
- package/build/swift-ui/SwipeActions/index.d.ts.map +1 -0
- package/build/swift-ui/index.d.ts +3 -0
- package/build/swift-ui/index.d.ts.map +1 -1
- package/build/swift-ui/modifiers/index.d.ts +3 -1
- package/build/swift-ui/modifiers/index.d.ts.map +1 -1
- package/build/swift-ui/modifiers/symbolEffect.d.ts +103 -0
- package/build/swift-ui/modifiers/symbolEffect.d.ts.map +1 -0
- package/build/swift-ui/withAnimation.d.ts +26 -0
- package/build/swift-ui/withAnimation.d.ts.map +1 -0
- package/build/universal/BottomSheet/index.android.d.ts +1 -1
- package/build/universal/BottomSheet/index.android.d.ts.map +1 -1
- package/build/universal/BottomSheet/index.d.ts +1 -1
- package/build/universal/BottomSheet/index.d.ts.map +1 -1
- package/build/universal/BottomSheet/index.ios.d.ts +1 -1
- package/build/universal/BottomSheet/index.ios.d.ts.map +1 -1
- package/build/universal/BottomSheet/types.d.ts +27 -0
- package/build/universal/BottomSheet/types.d.ts.map +1 -1
- package/build/universal/Collapsible/index.android.d.ts +8 -0
- package/build/universal/Collapsible/index.android.d.ts.map +1 -0
- package/build/universal/Collapsible/index.d.ts +8 -0
- package/build/universal/Collapsible/index.d.ts.map +1 -0
- package/build/universal/Collapsible/index.ios.d.ts +7 -0
- package/build/universal/Collapsible/index.ios.d.ts.map +1 -0
- package/build/universal/Collapsible/types.d.ts +23 -0
- package/build/universal/Collapsible/types.d.ts.map +1 -0
- package/build/universal/Column/index.d.ts.map +1 -1
- package/build/universal/Host/index.d.ts +5 -7
- package/build/universal/Host/index.d.ts.map +1 -1
- package/build/universal/Host/types.d.ts +72 -0
- package/build/universal/Host/types.d.ts.map +1 -0
- package/build/universal/List/index.android.d.ts +9 -0
- package/build/universal/List/index.android.d.ts.map +1 -0
- package/build/universal/List/index.d.ts +8 -0
- package/build/universal/List/index.d.ts.map +1 -0
- package/build/universal/List/index.ios.d.ts +8 -0
- package/build/universal/List/index.ios.d.ts.map +1 -0
- package/build/universal/List/types.d.ts +26 -0
- package/build/universal/List/types.d.ts.map +1 -0
- package/build/universal/ListItem/ListItem.android.d.ts +8 -0
- package/build/universal/ListItem/ListItem.android.d.ts.map +1 -0
- package/build/universal/ListItem/ListItem.d.ts +9 -0
- package/build/universal/ListItem/ListItem.d.ts.map +1 -0
- package/build/universal/ListItem/ListItem.ios.d.ts +8 -0
- package/build/universal/ListItem/ListItem.ios.d.ts.map +1 -0
- package/build/universal/ListItem/ListItemSlots.d.ts +21 -0
- package/build/universal/ListItem/ListItemSlots.d.ts.map +1 -0
- package/build/universal/ListItem/index.d.ts +10 -0
- package/build/universal/ListItem/index.d.ts.map +1 -0
- package/build/universal/ListItem/types.d.ts +59 -0
- package/build/universal/ListItem/types.d.ts.map +1 -0
- package/build/universal/Picker/Picker.android.d.ts +9 -0
- package/build/universal/Picker/Picker.android.d.ts.map +1 -0
- package/build/universal/Picker/Picker.d.ts +8 -0
- package/build/universal/Picker/Picker.d.ts.map +1 -0
- package/build/universal/Picker/Picker.ios.d.ts +9 -0
- package/build/universal/Picker/Picker.ios.d.ts.map +1 -0
- package/build/universal/Picker/PickerItem.d.ts +9 -0
- package/build/universal/Picker/PickerItem.d.ts.map +1 -0
- package/build/universal/Picker/index.d.ts +8 -0
- package/build/universal/Picker/index.d.ts.map +1 -0
- package/build/universal/Picker/types.d.ts +69 -0
- package/build/universal/Picker/types.d.ts.map +1 -0
- package/build/universal/index.d.ts +4 -0
- package/build/universal/index.d.ts.map +1 -1
- package/expo-module.config.json +1 -1
- package/ios/Alert/Alert.swift +56 -0
- package/ios/Alert/AlertProps.swift +8 -0
- package/ios/BottomSheetView.swift +4 -1
- package/ios/ExpoUIModule.swift +43 -1
- package/ios/ExpoUITouchHandlerHelper.h +4 -1
- package/ios/ExpoUITouchHandlerHelper.mm +1 -0
- package/ios/Modifiers/AnimationConfig.swift +109 -0
- package/ios/Modifiers/SwipeActionsModifier.swift +97 -0
- package/ios/Modifiers/SymbolEffectModifier.swift +452 -0
- package/ios/Modifiers/ViewModifierRegistry.swift +5 -112
- package/ios/SlotView.swift +5 -0
- package/ios/State/ObservableState.swift +12 -1
- 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
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha512 +1 -0
- 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
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha512 +1 -0
- 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
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
- package/package.json +7 -3
- package/src/State/useNativeState.ts +70 -10
- package/src/community/bottom-sheet/BottomSheet.ios.tsx +0 -17
- package/src/community/menu/MenuView.android.tsx +224 -0
- package/src/community/menu/MenuView.ios.tsx +149 -0
- package/src/community/menu/MenuView.tsx +36 -0
- package/src/community/menu/index.tsx +14 -0
- package/src/community/menu/types.tsx +171 -0
- package/src/jetpack-compose/LoadingIndicator/index.tsx +92 -0
- package/src/jetpack-compose/Snackbar/index.tsx +135 -0
- package/src/jetpack-compose/index.ts +2 -0
- package/src/jetpack-compose/modifiers/index.ts +30 -2
- package/src/swift-ui/Alert/index.tsx +87 -0
- package/src/swift-ui/BottomSheet/index.tsx +32 -15
- package/src/swift-ui/SlotView.tsx +17 -4
- package/src/swift-ui/SwipeActions/index.tsx +73 -0
- package/src/swift-ui/index.tsx +3 -0
- package/src/swift-ui/modifiers/index.ts +3 -0
- package/src/swift-ui/modifiers/symbolEffect.ts +181 -0
- package/src/swift-ui/withAnimation.ts +71 -0
- package/src/ts-declarations/react-native-web.d.ts +27 -0
- package/src/universal/BottomSheet/index.android.tsx +27 -3
- package/src/universal/BottomSheet/index.ios.tsx +30 -12
- package/src/universal/BottomSheet/index.tsx +46 -4
- package/src/universal/BottomSheet/types.ts +25 -0
- package/src/universal/Collapsible/index.android.tsx +72 -0
- package/src/universal/Collapsible/index.ios.tsx +16 -0
- package/src/universal/Collapsible/index.tsx +58 -0
- package/src/universal/Collapsible/types.ts +25 -0
- package/src/universal/Column/index.tsx +3 -1
- package/src/universal/Host/index.tsx +69 -5
- package/src/universal/Host/types.ts +70 -0
- package/src/universal/List/index.android.tsx +44 -0
- package/src/universal/List/index.ios.tsx +19 -0
- package/src/universal/List/index.tsx +26 -0
- package/src/universal/List/types.ts +28 -0
- package/src/universal/ListItem/ListItem.android.tsx +52 -0
- package/src/universal/ListItem/ListItem.ios.tsx +58 -0
- package/src/universal/ListItem/ListItem.tsx +72 -0
- package/src/universal/ListItem/ListItemSlots.tsx +66 -0
- package/src/universal/ListItem/index.ts +15 -0
- package/src/universal/ListItem/types.ts +67 -0
- package/src/universal/Picker/Picker.android.tsx +69 -0
- package/src/universal/Picker/Picker.ios.tsx +45 -0
- package/src/universal/Picker/Picker.tsx +52 -0
- package/src/universal/Picker/PickerItem.tsx +27 -0
- package/src/universal/Picker/index.ts +11 -0
- package/src/universal/Picker/types.ts +79 -0
- package/src/universal/index.ts +4 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha512 +0 -1
- package/src/community/bottom-sheet/CLAUDE.md +0 -55
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { requireNativeView } from 'expo';
|
|
2
|
+
import type { NativeSyntheticEvent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { Slot } from '../SlotView';
|
|
5
|
+
import { createViewModifierEventListener } from '../modifiers/utils';
|
|
6
|
+
import { type CommonViewModifierProps } from '../types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Props of the `Alert` component.
|
|
10
|
+
*/
|
|
11
|
+
export type AlertProps = {
|
|
12
|
+
/**
|
|
13
|
+
* The contents of the alert.
|
|
14
|
+
* Should include `Alert.Trigger`, `Alert.Actions`, and optionally `Alert.Message`.
|
|
15
|
+
*/
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
/**
|
|
18
|
+
* The title of the alert.
|
|
19
|
+
*/
|
|
20
|
+
title: string;
|
|
21
|
+
/**
|
|
22
|
+
* Whether the alert is presented.
|
|
23
|
+
*/
|
|
24
|
+
isPresented?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* A callback that is called when the `isPresented` state changes.
|
|
27
|
+
*/
|
|
28
|
+
onIsPresentedChange?: (isPresented: boolean) => void;
|
|
29
|
+
} & CommonViewModifierProps;
|
|
30
|
+
|
|
31
|
+
type NativeAlertProps = Omit<AlertProps, 'onIsPresentedChange'> & {
|
|
32
|
+
onIsPresentedChange?: (event: NativeSyntheticEvent<{ isPresented: boolean }>) => void;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const AlertNativeView: React.ComponentType<NativeAlertProps> = requireNativeView(
|
|
36
|
+
'ExpoUI',
|
|
37
|
+
'AlertView'
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The component visible all the time that triggers the alert presentation.
|
|
42
|
+
*/
|
|
43
|
+
function Trigger(props: { children: React.ReactNode }) {
|
|
44
|
+
return <Slot name="trigger">{props.children}</Slot>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The action buttons displayed in the alert. Use `Button` components from `@expo/ui/swift-ui` as children.
|
|
49
|
+
*/
|
|
50
|
+
function Actions(props: { children: React.ReactNode }) {
|
|
51
|
+
return <Slot name="actions">{props.children}</Slot>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* An optional message displayed below the title in the alert.
|
|
56
|
+
*/
|
|
57
|
+
function Message(props: { children: React.ReactNode }) {
|
|
58
|
+
return <Slot name="message">{props.children}</Slot>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* `Alert` presents a SwiftUI alert with a title, optional message, and action buttons.
|
|
63
|
+
*
|
|
64
|
+
* @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/alert(_:ispresented:actions:message:)).
|
|
65
|
+
*/
|
|
66
|
+
function Alert(props: AlertProps) {
|
|
67
|
+
const { onIsPresentedChange, modifiers, children, ...restProps } = props;
|
|
68
|
+
|
|
69
|
+
const handleIsPresentedChange = (event: NativeSyntheticEvent<{ isPresented: boolean }>) => {
|
|
70
|
+
onIsPresentedChange?.(event.nativeEvent.isPresented);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<AlertNativeView
|
|
75
|
+
{...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
|
|
76
|
+
{...restProps}
|
|
77
|
+
onIsPresentedChange={handleIsPresentedChange}>
|
|
78
|
+
{children}
|
|
79
|
+
</AlertNativeView>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Alert.Trigger = Trigger;
|
|
84
|
+
Alert.Actions = Actions;
|
|
85
|
+
Alert.Message = Message;
|
|
86
|
+
|
|
87
|
+
export { Alert };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { requireNativeView } from 'expo';
|
|
2
|
-
import type
|
|
2
|
+
import { useState, type ComponentType } from 'react';
|
|
3
3
|
import type { NativeSyntheticEvent } from 'react-native';
|
|
4
4
|
|
|
5
5
|
import { createViewModifierEventListener } from '../modifiers/utils';
|
|
@@ -21,6 +21,10 @@ export type BottomSheetProps = {
|
|
|
21
21
|
* Callback function that is called when the `BottomSheet` presented state changes.
|
|
22
22
|
*/
|
|
23
23
|
onIsPresentedChange: (isPresented: boolean) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Callback function that is called after the `BottomSheet` has been fully dismissed.
|
|
26
|
+
*/
|
|
27
|
+
onDismiss?: () => void;
|
|
24
28
|
/**
|
|
25
29
|
* When `true`, the sheet will automatically size itself to fit its content.
|
|
26
30
|
* This sets the presentation detent to match the height of the children.
|
|
@@ -29,8 +33,9 @@ export type BottomSheetProps = {
|
|
|
29
33
|
fitToContents?: boolean;
|
|
30
34
|
} & CommonViewModifierProps;
|
|
31
35
|
|
|
32
|
-
type NativeBottomSheetProps = Omit<BottomSheetProps, 'onIsPresentedChange'> & {
|
|
36
|
+
type NativeBottomSheetProps = Omit<BottomSheetProps, 'onIsPresentedChange' | 'onDismiss'> & {
|
|
33
37
|
onIsPresentedChange: (event: NativeSyntheticEvent<{ isPresented: boolean }>) => void;
|
|
38
|
+
onDismiss: (event: NativeSyntheticEvent<object>) => void;
|
|
34
39
|
};
|
|
35
40
|
|
|
36
41
|
const BottomSheetNativeView: ComponentType<NativeBottomSheetProps> = requireNativeView(
|
|
@@ -38,23 +43,35 @@ const BottomSheetNativeView: ComponentType<NativeBottomSheetProps> = requireNati
|
|
|
38
43
|
'BottomSheetView'
|
|
39
44
|
);
|
|
40
45
|
|
|
41
|
-
function transformBottomSheetProps(props: BottomSheetProps): NativeBottomSheetProps {
|
|
42
|
-
const { modifiers, ...restProps } = props;
|
|
43
|
-
return {
|
|
44
|
-
modifiers,
|
|
45
|
-
...(modifiers ? createViewModifierEventListener(modifiers) : undefined),
|
|
46
|
-
...restProps,
|
|
47
|
-
onIsPresentedChange: ({ nativeEvent: { isPresented } }) => {
|
|
48
|
-
props?.onIsPresentedChange?.(isPresented);
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
46
|
/**
|
|
54
47
|
* `BottomSheet` presents content from the bottom of the screen.
|
|
55
48
|
*/
|
|
56
49
|
function BottomSheet(props: BottomSheetProps) {
|
|
57
|
-
|
|
50
|
+
const { modifiers, onIsPresentedChange, onDismiss, ...restProps } = props;
|
|
51
|
+
const [isMounted, setIsMounted] = useState(props.isPresented);
|
|
52
|
+
|
|
53
|
+
if (props.isPresented && !isMounted) {
|
|
54
|
+
setIsMounted(true);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!isMounted) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<BottomSheetNativeView
|
|
63
|
+
modifiers={modifiers}
|
|
64
|
+
{...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
|
|
65
|
+
{...restProps}
|
|
66
|
+
onIsPresentedChange={({ nativeEvent: { isPresented } }) => {
|
|
67
|
+
onIsPresentedChange?.(isPresented);
|
|
68
|
+
}}
|
|
69
|
+
onDismiss={() => {
|
|
70
|
+
setIsMounted(false);
|
|
71
|
+
onDismiss?.();
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
58
75
|
}
|
|
59
76
|
|
|
60
77
|
export { BottomSheet };
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import { requireNativeView } from 'expo';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
type SlotProps<ExtraProps extends Record<string, unknown> = Record<string, unknown>> = {
|
|
4
|
+
name: string;
|
|
5
|
+
extraProps?: ExtraProps;
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
};
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
const SlotNativeView: React.ComponentType<SlotProps> = requireNativeView('ExpoUI', 'SlotView');
|
|
10
|
+
|
|
11
|
+
export function Slot<ExtraProps extends Record<string, unknown> = Record<string, unknown>>({
|
|
12
|
+
name,
|
|
13
|
+
extraProps,
|
|
14
|
+
children,
|
|
15
|
+
}: SlotProps<ExtraProps>) {
|
|
16
|
+
return (
|
|
17
|
+
<SlotNativeView name={name} extraProps={extraProps}>
|
|
18
|
+
{children}
|
|
19
|
+
</SlotNativeView>
|
|
20
|
+
);
|
|
8
21
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
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 type SwipeActionsEdge = 'leading' | 'trailing';
|
|
8
|
+
|
|
9
|
+
export type SwipeActionsProps = {
|
|
10
|
+
/**
|
|
11
|
+
* The regular content and `SwipeActions.Actions` action groups.
|
|
12
|
+
*/
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
} & CommonViewModifierProps;
|
|
15
|
+
|
|
16
|
+
export type SwipeActionsGroupProps = {
|
|
17
|
+
/**
|
|
18
|
+
* The edge where these swipe actions are revealed.
|
|
19
|
+
* @default 'trailing'
|
|
20
|
+
*/
|
|
21
|
+
edge?: SwipeActionsEdge;
|
|
22
|
+
/**
|
|
23
|
+
* Whether a full swipe automatically performs the first action in this group.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
allowsFullSwipe?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The buttons revealed when the user swipes from this edge.
|
|
29
|
+
*/
|
|
30
|
+
children: React.ReactNode;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type SwipeActionsNativeProps = SwipeActionsProps;
|
|
34
|
+
|
|
35
|
+
const SwipeActionsNativeView: React.ComponentType<SwipeActionsNativeProps> = requireNativeView(
|
|
36
|
+
'ExpoUI',
|
|
37
|
+
'SwipeActionsView'
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The buttons revealed when the user swipes the regular content from an edge.
|
|
42
|
+
*/
|
|
43
|
+
export function Actions({
|
|
44
|
+
edge = 'trailing',
|
|
45
|
+
allowsFullSwipe = true,
|
|
46
|
+
children,
|
|
47
|
+
}: SwipeActionsGroupProps) {
|
|
48
|
+
return (
|
|
49
|
+
<Slot name="actions" extraProps={{ edge, allowsFullSwipe }}>
|
|
50
|
+
{children}
|
|
51
|
+
</Slot>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Applies native SwiftUI swipe actions to its non-slot children.
|
|
57
|
+
* @platform ios
|
|
58
|
+
*/
|
|
59
|
+
function SwipeActionsComponent(props: SwipeActionsProps) {
|
|
60
|
+
const { modifiers, ...restProps } = props;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<SwipeActionsNativeView
|
|
64
|
+
modifiers={modifiers}
|
|
65
|
+
{...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
|
|
66
|
+
{...restProps}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const SwipeActions = Object.assign(SwipeActionsComponent, { Actions });
|
|
72
|
+
|
|
73
|
+
export { SwipeActions };
|
package/src/swift-ui/index.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '../State/index.fx';
|
|
2
2
|
|
|
3
3
|
export * from './AccessoryWidgetBackground';
|
|
4
|
+
export * from './Alert';
|
|
4
5
|
export * from './BottomSheet';
|
|
5
6
|
export * from './Button';
|
|
6
7
|
export * from './Chart';
|
|
@@ -33,8 +34,10 @@ export * from './ShareLink';
|
|
|
33
34
|
export * from './Slider';
|
|
34
35
|
export * from './Spacer';
|
|
35
36
|
export * from './Stepper';
|
|
37
|
+
export * from './SwipeActions';
|
|
36
38
|
export * from './Text';
|
|
37
39
|
export { useNativeState } from '../State/useNativeState';
|
|
40
|
+
export { withAnimation, type WithAnimationCompletionCriteria } from './withAnimation';
|
|
38
41
|
export * from './SyncToggle';
|
|
39
42
|
export * from './TabView';
|
|
40
43
|
export * from './Toggle';
|
|
@@ -20,6 +20,7 @@ import { environment } from './environment';
|
|
|
20
20
|
import { gaugeStyle } from './gaugeStyle';
|
|
21
21
|
import { progressViewStyle } from './progressViewStyle';
|
|
22
22
|
import { id, scrollPosition } from './scrollPosition';
|
|
23
|
+
import { symbolEffect } from './symbolEffect';
|
|
23
24
|
import type { Color } from './types';
|
|
24
25
|
import { widgetAccentedRenderingMode, widgetURL } from './widgets';
|
|
25
26
|
|
|
@@ -1376,6 +1377,7 @@ export type BuiltInModifier =
|
|
|
1376
1377
|
| ReturnType<typeof listStyle>
|
|
1377
1378
|
| ReturnType<typeof contentTransition>
|
|
1378
1379
|
| ReturnType<typeof resizable>
|
|
1380
|
+
| ReturnType<typeof symbolEffect>
|
|
1379
1381
|
| ReturnType<typeof widgetAccentedRenderingMode>
|
|
1380
1382
|
| ReturnType<typeof widgetURL>
|
|
1381
1383
|
| ReturnType<typeof containerBackground>;
|
|
@@ -1426,6 +1428,7 @@ export * from './gaugeStyle';
|
|
|
1426
1428
|
export * from './presentationModifiers';
|
|
1427
1429
|
export * from './environment';
|
|
1428
1430
|
export * from './scrollPosition';
|
|
1431
|
+
export * from './symbolEffect';
|
|
1429
1432
|
export * from './widgets';
|
|
1430
1433
|
export type {
|
|
1431
1434
|
TimingAnimationParams,
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createModifier } from './createModifier';
|
|
2
|
+
import { type ObservableState } from '../../State/useNativeState';
|
|
3
|
+
import { getStateId } from '../../State/utils';
|
|
4
|
+
|
|
5
|
+
// https://developer.apple.com/documentation/symbols/appearsymboleffect
|
|
6
|
+
type AppearSymbolEffect = {
|
|
7
|
+
effect: 'appear';
|
|
8
|
+
scale?: 'down' | 'up';
|
|
9
|
+
scope?: 'byLayer' | 'wholeSymbol';
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// https://developer.apple.com/documentation/symbols/bouncesymboleffect
|
|
13
|
+
type BounceSymbolEffect = {
|
|
14
|
+
effect: 'bounce';
|
|
15
|
+
direction?: 'down' | 'up';
|
|
16
|
+
scope?: 'byLayer' | 'wholeSymbol';
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// https://developer.apple.com/documentation/symbols/breathesymboleffect
|
|
20
|
+
type BreatheSymbolEffect = {
|
|
21
|
+
effect: 'breathe';
|
|
22
|
+
style?: 'plain' | 'pulse';
|
|
23
|
+
scope?: 'byLayer' | 'wholeSymbol';
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// https://developer.apple.com/documentation/symbols/disappearsymboleffect
|
|
27
|
+
type DisappearSymbolEffect = {
|
|
28
|
+
effect: 'disappear';
|
|
29
|
+
scale?: 'down' | 'up';
|
|
30
|
+
scope?: 'byLayer' | 'wholeSymbol';
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// https://developer.apple.com/documentation/symbols/drawoffsymboleffect
|
|
34
|
+
type DrawOffSymbolEffect = {
|
|
35
|
+
effect: 'drawOff';
|
|
36
|
+
playbackStyle?: 'nonReversed' | 'reversed';
|
|
37
|
+
scope?: 'byLayer' | 'individually' | 'wholeSymbol';
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// https://developer.apple.com/documentation/symbols/drawonsymboleffect
|
|
41
|
+
type DrawOnSymbolEffect = {
|
|
42
|
+
effect: 'drawOn';
|
|
43
|
+
scope?: 'byLayer' | 'individually' | 'wholeSymbol';
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// https://developer.apple.com/documentation/symbols/pulsesymboleffect
|
|
47
|
+
type PulseSymbolEffect = {
|
|
48
|
+
effect: 'pulse';
|
|
49
|
+
scope?: 'byLayer' | 'wholeSymbol';
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// https://developer.apple.com/documentation/symbols/rotatesymboleffect
|
|
53
|
+
type RotateSymbolEffect = {
|
|
54
|
+
effect: 'rotate';
|
|
55
|
+
direction?: 'clockwise' | 'counterClockwise';
|
|
56
|
+
scope?: 'byLayer' | 'wholeSymbol';
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// https://developer.apple.com/documentation/symbols/scalesymboleffect
|
|
60
|
+
type ScaleSymbolEffect = {
|
|
61
|
+
effect: 'scale';
|
|
62
|
+
scale?: 'down' | 'up';
|
|
63
|
+
scope?: 'byLayer' | 'wholeSymbol';
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// https://developer.apple.com/documentation/symbols/variablecolorsymboleffect
|
|
67
|
+
type VariableColorSymbolEffect = {
|
|
68
|
+
effect: 'variableColor';
|
|
69
|
+
fillStyle?: 'cumulative' | 'iterative';
|
|
70
|
+
playbackStyle?: 'nonReversing' | 'reversing';
|
|
71
|
+
inactiveLayers?: 'dim' | 'hide';
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// https://developer.apple.com/documentation/symbols/wigglesymboleffect
|
|
75
|
+
type WiggleSymbolEffect = {
|
|
76
|
+
effect: 'wiggle';
|
|
77
|
+
direction?:
|
|
78
|
+
| 'backward'
|
|
79
|
+
| 'clockwise'
|
|
80
|
+
| 'counterClockwise'
|
|
81
|
+
| 'down'
|
|
82
|
+
| 'forward'
|
|
83
|
+
| 'left'
|
|
84
|
+
| 'right'
|
|
85
|
+
| 'up';
|
|
86
|
+
// Custom wiggle angle in degrees. Takes precedence over `direction` when set.
|
|
87
|
+
customAngle?: number;
|
|
88
|
+
scope?: 'byLayer' | 'wholeSymbol';
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export type SymbolEffect =
|
|
92
|
+
| AppearSymbolEffect
|
|
93
|
+
| BounceSymbolEffect
|
|
94
|
+
| BreatheSymbolEffect
|
|
95
|
+
| DisappearSymbolEffect
|
|
96
|
+
| DrawOffSymbolEffect
|
|
97
|
+
| DrawOnSymbolEffect
|
|
98
|
+
| PulseSymbolEffect
|
|
99
|
+
| RotateSymbolEffect
|
|
100
|
+
| ScaleSymbolEffect
|
|
101
|
+
| VariableColorSymbolEffect
|
|
102
|
+
| WiggleSymbolEffect;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Animation options for a symbol effect.
|
|
106
|
+
*
|
|
107
|
+
* @see Official [Apple documentation](https://developer.apple.com/documentation/symbols/symboleffectoptions).
|
|
108
|
+
*/
|
|
109
|
+
export type SymbolEffectOptions = {
|
|
110
|
+
/**
|
|
111
|
+
* How the effect repeats. Omit for the effect's natural cadence.
|
|
112
|
+
* - `'nonRepeating'` — play exactly once.
|
|
113
|
+
* - `'continuous'` — smooth, indefinite repetition (iOS 18+).
|
|
114
|
+
* - `{ count?, delay? }` — periodic repetition with optional count and delay in seconds (iOS 18+).
|
|
115
|
+
*/
|
|
116
|
+
repeat?: 'continuous' | 'nonRepeating' | { count?: number; delay?: number };
|
|
117
|
+
/** Animation speed multiplier (1.0 = default). */
|
|
118
|
+
speed?: number;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/** Equatable primitive accepted as a discrete effect trigger. */
|
|
122
|
+
export type DiscreteSymbolEffectValue = number | string | boolean;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Applies an SF Symbol effect to a view.
|
|
126
|
+
*
|
|
127
|
+
* @platform ios 17.0+
|
|
128
|
+
* @platform tvos 17.0+
|
|
129
|
+
* @see Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/symbolEffect(_:options:value:)).
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```tsx
|
|
133
|
+
* const trigger = useNativeState(0);
|
|
134
|
+
* <Image
|
|
135
|
+
* systemName="bell.fill"
|
|
136
|
+
* modifiers={[symbolEffect({ effect: 'bounce', direction: 'up' }, { value: trigger })]}
|
|
137
|
+
* />
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export const symbolEffect = (
|
|
141
|
+
effect: SymbolEffect,
|
|
142
|
+
args: {
|
|
143
|
+
options?: SymbolEffectOptions;
|
|
144
|
+
/** Indefinite effects: runs while `state.value === true`. Default active when omitted. */
|
|
145
|
+
isActive?: ObservableState<boolean>;
|
|
146
|
+
/** Discrete effects: the effect fires once each time this value changes. */
|
|
147
|
+
value?: ObservableState<DiscreteSymbolEffectValue>;
|
|
148
|
+
} = {}
|
|
149
|
+
) => {
|
|
150
|
+
const { options, isActive, value } = args;
|
|
151
|
+
return createModifier('symbolEffect', {
|
|
152
|
+
effect,
|
|
153
|
+
options: flattenOptions(options),
|
|
154
|
+
isActive: isActive ? getStateId(isActive) : undefined,
|
|
155
|
+
value: value ? getStateId(value) : undefined,
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
function flattenOptions(options?: SymbolEffectOptions) {
|
|
160
|
+
if (!options) return undefined;
|
|
161
|
+
const { speed } = options;
|
|
162
|
+
const repeatField = options.repeat;
|
|
163
|
+
if (repeatField === undefined) {
|
|
164
|
+
return { speed };
|
|
165
|
+
}
|
|
166
|
+
if (repeatField === 'nonRepeating') {
|
|
167
|
+
return { repeatKind: 'nonRepeating' as const, speed };
|
|
168
|
+
}
|
|
169
|
+
if (repeatField === 'continuous') {
|
|
170
|
+
return { repeatKind: 'continuous' as const, speed };
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
repeatKind: 'periodic' as const,
|
|
174
|
+
repeatCount: repeatField.count,
|
|
175
|
+
repeatDelay: repeatField.delay,
|
|
176
|
+
speed,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// exported for docs api data
|
|
181
|
+
export { type ObservableState };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { requireNativeModule } from 'expo';
|
|
2
|
+
|
|
3
|
+
import { worklets } from '../State/optionalWorklets';
|
|
4
|
+
import { VALUE_SYMBOL } from './modifiers/animation/constants';
|
|
5
|
+
import type { AnimationObject, ChainableAnimationType } from './modifiers/animation/types';
|
|
6
|
+
|
|
7
|
+
const ExpoUI = requireNativeModule('ExpoUI');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/animationcompletioncriteria).
|
|
11
|
+
*/
|
|
12
|
+
export type WithAnimationCompletionCriteria = 'logicallyComplete' | 'removed';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Mirrors SwiftUI's [`withAnimation(_:_:)`](https://developer.apple.com/documentation/swiftui/withanimation(_:_:)).
|
|
16
|
+
* The body must be a worklet so the mutations run synchronously on the
|
|
17
|
+
* UI thread inside the animation transaction.
|
|
18
|
+
*
|
|
19
|
+
* Performs `body` inside a SwiftUI animation transaction. Any
|
|
20
|
+
* `useNativeState` values mutated by the worklet animate to their new value
|
|
21
|
+
* using `animation`.
|
|
22
|
+
*
|
|
23
|
+
* @param animation Animation to apply, built with the `Animation` factory
|
|
24
|
+
* from `@expo/ui/swift-ui/modifiers`. Pass `null` to run `body` without an
|
|
25
|
+
* animation.
|
|
26
|
+
* @param body Worklet that mutates one or more `useNativeState` values.
|
|
27
|
+
* @param completion Optional worklet invoked on the main thread when the
|
|
28
|
+
* animation finishes. Requires iOS 17 / tvOS 17; on earlier versions the
|
|
29
|
+
* animation still runs but the callback is silently skipped.
|
|
30
|
+
* @param completionCriteria Controls when `completion` fires. Defaults to
|
|
31
|
+
* `'logicallyComplete'`.
|
|
32
|
+
*/
|
|
33
|
+
export function withAnimation(
|
|
34
|
+
animation: ChainableAnimationType | null,
|
|
35
|
+
body: () => void,
|
|
36
|
+
completion?: () => void,
|
|
37
|
+
completionCriteria?: WithAnimationCompletionCriteria
|
|
38
|
+
): void {
|
|
39
|
+
if (!worklets) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"withAnimation needs the 'react-native-worklets' package, which couldn't be loaded. " +
|
|
42
|
+
'Install react-native-worklets and rebuild the native app, then call withAnimation again.'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!worklets.isWorkletFunction(body)) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
'withAnimation body must be a worklet. Worklets run synchronously on the UI thread ' +
|
|
49
|
+
"so state changes are captured by SwiftUI's animation transaction. " +
|
|
50
|
+
"Add the 'worklet' directive as the first statement: " +
|
|
51
|
+
"() => { 'worklet'; state.value = next; }."
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let completionCallback: object | null = null;
|
|
56
|
+
if (completion) {
|
|
57
|
+
if (!worklets.isWorkletFunction(completion)) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
"withAnimation completion must be a worklet. Add the 'worklet' directive as the " +
|
|
60
|
+
'first statement in your completion callback.'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
completionCallback = new ExpoUI.WorkletCallback(worklets.createSerializable(completion));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const animationObject: AnimationObject | null =
|
|
67
|
+
animation == null ? null : animation[VALUE_SYMBOL]();
|
|
68
|
+
|
|
69
|
+
const bodyCallback = new ExpoUI.WorkletCallback(worklets.createSerializable(body));
|
|
70
|
+
ExpoUI.withAnimation(animationObject, bodyCallback, completionCallback, completionCriteria);
|
|
71
|
+
}
|
|
@@ -7,6 +7,8 @@ declare module 'react-native' {
|
|
|
7
7
|
) => React.ReactElement<P>;
|
|
8
8
|
|
|
9
9
|
type DisplayValue = ReactNative.FlexStyle['display'] | 'inline-flex';
|
|
10
|
+
type OverflowValue = 'auto' | 'hidden' | 'scroll' | 'visible';
|
|
11
|
+
type WebDimensionValue = ReactNative.DimensionValue | string;
|
|
10
12
|
|
|
11
13
|
type WebRole =
|
|
12
14
|
| ReactNative.Role
|
|
@@ -95,18 +97,43 @@ declare module 'react-native' {
|
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
export interface ViewProps extends WebAccessibilityProps {
|
|
100
|
+
dir?: string;
|
|
98
101
|
role?: WebRole;
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
export interface ImageStyle {
|
|
102
105
|
display?: DisplayValue;
|
|
106
|
+
height?: WebDimensionValue;
|
|
107
|
+
width?: WebDimensionValue;
|
|
108
|
+
overflowX?: OverflowValue;
|
|
109
|
+
overflowY?: OverflowValue;
|
|
110
|
+
paddingLeft?: WebDimensionValue;
|
|
111
|
+
paddingRight?: WebDimensionValue;
|
|
112
|
+
paddingTop?: WebDimensionValue;
|
|
113
|
+
paddingBottom?: WebDimensionValue;
|
|
103
114
|
}
|
|
104
115
|
|
|
105
116
|
export interface TextStyle {
|
|
106
117
|
display?: DisplayValue;
|
|
118
|
+
height?: WebDimensionValue;
|
|
119
|
+
width?: WebDimensionValue;
|
|
120
|
+
overflowX?: OverflowValue;
|
|
121
|
+
overflowY?: OverflowValue;
|
|
122
|
+
paddingLeft?: WebDimensionValue;
|
|
123
|
+
paddingRight?: WebDimensionValue;
|
|
124
|
+
paddingTop?: WebDimensionValue;
|
|
125
|
+
paddingBottom?: WebDimensionValue;
|
|
107
126
|
}
|
|
108
127
|
|
|
109
128
|
export interface ViewStyle {
|
|
110
129
|
display?: DisplayValue;
|
|
130
|
+
height?: WebDimensionValue;
|
|
131
|
+
width?: WebDimensionValue;
|
|
132
|
+
overflowX?: OverflowValue;
|
|
133
|
+
overflowY?: OverflowValue;
|
|
134
|
+
paddingLeft?: WebDimensionValue;
|
|
135
|
+
paddingRight?: WebDimensionValue;
|
|
136
|
+
paddingTop?: WebDimensionValue;
|
|
137
|
+
paddingBottom?: WebDimensionValue;
|
|
111
138
|
}
|
|
112
139
|
}
|
|
@@ -1,32 +1,56 @@
|
|
|
1
1
|
import { Column, ModalBottomSheet } from '@expo/ui/jetpack-compose';
|
|
2
2
|
import {
|
|
3
|
+
fillMaxHeight,
|
|
3
4
|
padding,
|
|
4
5
|
testID as testIDModifier,
|
|
5
6
|
type ModifierConfig,
|
|
6
7
|
} from '@expo/ui/jetpack-compose/modifiers';
|
|
7
8
|
|
|
8
|
-
import type { BottomSheetProps } from './types';
|
|
9
|
+
import type { BottomSheetProps, SnapPoint } from './types';
|
|
10
|
+
|
|
11
|
+
// M3 `ModalBottomSheet` only has partial/expanded states.
|
|
12
|
+
// Only allow the partial state when the consumer requested a partial-friendly snap point.
|
|
13
|
+
function shouldSkipPartiallyExpanded(snapPoints: SnapPoint[] | undefined): boolean {
|
|
14
|
+
if (!snapPoints || snapPoints.length === 0) return false;
|
|
15
|
+
return !snapPoints.some(
|
|
16
|
+
(sp) =>
|
|
17
|
+
sp === 'half' ||
|
|
18
|
+
(typeof sp === 'object' && 'fraction' in sp && sp.fraction < 1) ||
|
|
19
|
+
(typeof sp === 'object' && 'height' in sp)
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// M3 sizes content to intrinsic height.
|
|
24
|
+
// Apply `fillMaxHeight` so `'full'` actually fills the viewport instead of stopping at content height.
|
|
25
|
+
function shouldFillMaxHeight(snapPoints: SnapPoint[] | undefined): boolean {
|
|
26
|
+
if (!snapPoints || snapPoints.length === 0) return false;
|
|
27
|
+
return snapPoints.some(
|
|
28
|
+
(sp) => sp === 'full' || (typeof sp === 'object' && 'fraction' in sp && sp.fraction >= 1)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
9
31
|
|
|
10
32
|
export function BottomSheet({
|
|
11
33
|
children,
|
|
12
34
|
isPresented,
|
|
13
35
|
onDismiss,
|
|
14
36
|
showDragIndicator = true,
|
|
37
|
+
snapPoints,
|
|
15
38
|
testID,
|
|
16
39
|
modifiers,
|
|
17
40
|
}: BottomSheetProps) {
|
|
18
41
|
if (!isPresented) return null;
|
|
19
42
|
|
|
20
43
|
const contentModifiers: ModifierConfig[] = [padding(16, showDragIndicator ? 0 : 16, 16, 0)];
|
|
44
|
+
if (shouldFillMaxHeight(snapPoints)) contentModifiers.push(fillMaxHeight());
|
|
21
45
|
if (testID) contentModifiers.push(testIDModifier(testID));
|
|
22
46
|
|
|
23
47
|
return (
|
|
24
48
|
<ModalBottomSheet
|
|
25
49
|
onDismissRequest={onDismiss}
|
|
26
50
|
showDragHandle={showDragIndicator}
|
|
51
|
+
skipPartiallyExpanded={shouldSkipPartiallyExpanded(snapPoints)}
|
|
27
52
|
modifiers={modifiers}>
|
|
28
|
-
{/* When the drag handle is hidden, add top padding so content doesn't
|
|
29
|
-
crop against the top edge of the sheet. */}
|
|
53
|
+
{/* When the drag handle is hidden, add top padding so content doesn't crop against the top edge of the sheet. */}
|
|
30
54
|
<Column modifiers={contentModifiers}>{children}</Column>
|
|
31
55
|
</ModalBottomSheet>
|
|
32
56
|
);
|