blend-native 0.0.1-beta.0
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/README.md +404 -0
- package/lib/commonjs/a11y/announcement.js +42 -0
- package/lib/commonjs/a11y/announcement.js.map +1 -0
- package/lib/commonjs/a11y/useLiveRegion.js +37 -0
- package/lib/commonjs/a11y/useLiveRegion.js.map +1 -0
- package/lib/commonjs/adapters/cssStringAdapter.js +363 -0
- package/lib/commonjs/adapters/cssStringAdapter.js.map +1 -0
- package/lib/commonjs/adapters/optionalGradient.js +33 -0
- package/lib/commonjs/adapters/optionalGradient.js.map +1 -0
- package/lib/commonjs/adapters/surfaceStyle.js +159 -0
- package/lib/commonjs/adapters/surfaceStyle.js.map +1 -0
- package/lib/commonjs/components/Alert/Alert.js +130 -0
- package/lib/commonjs/components/Alert/Alert.js.map +1 -0
- package/lib/commonjs/components/Alert/AlertActions.js +74 -0
- package/lib/commonjs/components/Alert/AlertActions.js.map +1 -0
- package/lib/commonjs/components/Alert/AlertClose.js +48 -0
- package/lib/commonjs/components/Alert/AlertClose.js.map +1 -0
- package/lib/commonjs/components/Alert/AlertText.js +49 -0
- package/lib/commonjs/components/Alert/AlertText.js.map +1 -0
- package/lib/commonjs/components/Alert/alert.tokens.js +6 -0
- package/lib/commonjs/components/Alert/alert.tokens.js.map +1 -0
- package/lib/commonjs/components/Alert/alert.types.js +6 -0
- package/lib/commonjs/components/Alert/alert.types.js.map +1 -0
- package/lib/commonjs/components/Alert/alert.utils.js +80 -0
- package/lib/commonjs/components/Alert/alert.utils.js.map +1 -0
- package/lib/commonjs/components/Alert/index.js +51 -0
- package/lib/commonjs/components/Alert/index.js.map +1 -0
- package/lib/commonjs/components/Button/Button.js +125 -0
- package/lib/commonjs/components/Button/Button.js.map +1 -0
- package/lib/commonjs/components/Button/button.types.js +6 -0
- package/lib/commonjs/components/Button/button.types.js.map +1 -0
- package/lib/commonjs/components/Button/button.utils.js +129 -0
- package/lib/commonjs/components/Button/button.utils.js.map +1 -0
- package/lib/commonjs/components/Button/index.js +57 -0
- package/lib/commonjs/components/Button/index.js.map +1 -0
- package/lib/commonjs/components/Skeleton/Skeleton.js +154 -0
- package/lib/commonjs/components/Skeleton/Skeleton.js.map +1 -0
- package/lib/commonjs/components/Skeleton/index.js +20 -0
- package/lib/commonjs/components/Skeleton/index.js.map +1 -0
- package/lib/commonjs/components/Skeleton/skeleton.types.js +6 -0
- package/lib/commonjs/components/Skeleton/skeleton.types.js.map +1 -0
- package/lib/commonjs/components/Skeleton/skeleton.utils.js +45 -0
- package/lib/commonjs/components/Skeleton/skeleton.utils.js.map +1 -0
- package/lib/commonjs/components/Tag/Tag.js +161 -0
- package/lib/commonjs/components/Tag/Tag.js.map +1 -0
- package/lib/commonjs/components/Tag/index.js +33 -0
- package/lib/commonjs/components/Tag/index.js.map +1 -0
- package/lib/commonjs/components/Tag/tag.types.js +6 -0
- package/lib/commonjs/components/Tag/tag.types.js.map +1 -0
- package/lib/commonjs/components/Tag/tag.utils.js +69 -0
- package/lib/commonjs/components/Tag/tag.utils.js.map +1 -0
- package/lib/commonjs/components/TextInput/TextInput.js +138 -0
- package/lib/commonjs/components/TextInput/TextInput.js.map +1 -0
- package/lib/commonjs/components/TextInput/index.js +14 -0
- package/lib/commonjs/components/TextInput/index.js.map +1 -0
- package/lib/commonjs/components/TextInput/textInput.types.js +6 -0
- package/lib/commonjs/components/TextInput/textInput.types.js.map +1 -0
- package/lib/commonjs/components/TextInput/textInput.utils.js +40 -0
- package/lib/commonjs/components/TextInput/textInput.utils.js.map +1 -0
- package/lib/commonjs/components/shared/field/FieldFooter.js +51 -0
- package/lib/commonjs/components/shared/field/FieldFooter.js.map +1 -0
- package/lib/commonjs/components/shared/field/FieldLabels.js +67 -0
- package/lib/commonjs/components/shared/field/FieldLabels.js.map +1 -0
- package/lib/commonjs/components/shared/field/fieldState.js +37 -0
- package/lib/commonjs/components/shared/field/fieldState.js.map +1 -0
- package/lib/commonjs/components/shared/group.js +73 -0
- package/lib/commonjs/components/shared/group.js.map +1 -0
- package/lib/commonjs/index.js +256 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/motion/motion.js +128 -0
- package/lib/commonjs/motion/motion.js.map +1 -0
- package/lib/commonjs/motion/useReduceMotion.js +37 -0
- package/lib/commonjs/motion/useReduceMotion.js.map +1 -0
- package/lib/commonjs/overlay/portal.js +110 -0
- package/lib/commonjs/overlay/portal.js.map +1 -0
- package/lib/commonjs/overlay/positioning.js +122 -0
- package/lib/commonjs/overlay/positioning.js.map +1 -0
- package/lib/commonjs/overlay/safeAreaInsets.js +30 -0
- package/lib/commonjs/overlay/safeAreaInsets.js.map +1 -0
- package/lib/commonjs/overlay/sheet/BottomSheet.js +196 -0
- package/lib/commonjs/overlay/sheet/BottomSheet.js.map +1 -0
- package/lib/commonjs/overlay/sheet/sheetMath.js +60 -0
- package/lib/commonjs/overlay/sheet/sheetMath.js.map +1 -0
- package/lib/commonjs/overlay/toast/ToastOutlet.js +106 -0
- package/lib/commonjs/overlay/toast/ToastOutlet.js.map +1 -0
- package/lib/commonjs/overlay/toast/toastStore.js +76 -0
- package/lib/commonjs/overlay/toast/toastStore.js.map +1 -0
- package/lib/commonjs/overlay/useAnchoredPosition.js +85 -0
- package/lib/commonjs/overlay/useAnchoredPosition.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/primitives/Block.js +112 -0
- package/lib/commonjs/primitives/Block.js.map +1 -0
- package/lib/commonjs/primitives/Pressable.js +348 -0
- package/lib/commonjs/primitives/Pressable.js.map +1 -0
- package/lib/commonjs/primitives/PrimitiveInput.js +66 -0
- package/lib/commonjs/primitives/PrimitiveInput.js.map +1 -0
- package/lib/commonjs/primitives/Separator.js +55 -0
- package/lib/commonjs/primitives/Separator.js.map +1 -0
- package/lib/commonjs/primitives/Slot.js +78 -0
- package/lib/commonjs/primitives/Slot.js.map +1 -0
- package/lib/commonjs/primitives/Text.js +73 -0
- package/lib/commonjs/primitives/Text.js.map +1 -0
- package/lib/commonjs/primitives/pressFeedback.js +53 -0
- package/lib/commonjs/primitives/pressFeedback.js.map +1 -0
- package/lib/commonjs/primitives/textStyle.js +27 -0
- package/lib/commonjs/primitives/textStyle.js.map +1 -0
- package/lib/commonjs/primitives/tintSlot.js +45 -0
- package/lib/commonjs/primitives/tintSlot.js.map +1 -0
- package/lib/commonjs/primitives/touchTarget.js +64 -0
- package/lib/commonjs/primitives/touchTarget.js.map +1 -0
- package/lib/commonjs/theme/BlendNativeProvider.js +90 -0
- package/lib/commonjs/theme/BlendNativeProvider.js.map +1 -0
- package/lib/commonjs/theme/breakpoint.js +36 -0
- package/lib/commonjs/theme/breakpoint.js.map +1 -0
- package/lib/commonjs/theme/fonts.js +58 -0
- package/lib/commonjs/theme/fonts.js.map +1 -0
- package/lib/commonjs/theme/nativeTokenRegistry.js +44 -0
- package/lib/commonjs/theme/nativeTokenRegistry.js.map +1 -0
- package/lib/commonjs/theme/systemTheme.js +35 -0
- package/lib/commonjs/theme/systemTheme.js.map +1 -0
- package/lib/commonjs/theme/useNativeBreakpoint.js +33 -0
- package/lib/commonjs/theme/useNativeBreakpoint.js.map +1 -0
- package/lib/commonjs/theme/useNativeTokens.js +71 -0
- package/lib/commonjs/theme/useNativeTokens.js.map +1 -0
- package/lib/module/a11y/announcement.js +38 -0
- package/lib/module/a11y/announcement.js.map +1 -0
- package/lib/module/a11y/useLiveRegion.js +33 -0
- package/lib/module/a11y/useLiveRegion.js.map +1 -0
- package/lib/module/adapters/cssStringAdapter.js +352 -0
- package/lib/module/adapters/cssStringAdapter.js.map +1 -0
- package/lib/module/adapters/optionalGradient.js +29 -0
- package/lib/module/adapters/optionalGradient.js.map +1 -0
- package/lib/module/adapters/surfaceStyle.js +155 -0
- package/lib/module/adapters/surfaceStyle.js.map +1 -0
- package/lib/module/components/Alert/Alert.js +126 -0
- package/lib/module/components/Alert/Alert.js.map +1 -0
- package/lib/module/components/Alert/AlertActions.js +70 -0
- package/lib/module/components/Alert/AlertActions.js.map +1 -0
- package/lib/module/components/Alert/AlertClose.js +44 -0
- package/lib/module/components/Alert/AlertClose.js.map +1 -0
- package/lib/module/components/Alert/AlertText.js +45 -0
- package/lib/module/components/Alert/AlertText.js.map +1 -0
- package/lib/module/components/Alert/alert.tokens.js +4 -0
- package/lib/module/components/Alert/alert.tokens.js.map +1 -0
- package/lib/module/components/Alert/alert.types.js +4 -0
- package/lib/module/components/Alert/alert.types.js.map +1 -0
- package/lib/module/components/Alert/alert.utils.js +72 -0
- package/lib/module/components/Alert/alert.utils.js.map +1 -0
- package/lib/module/components/Alert/index.js +6 -0
- package/lib/module/components/Alert/index.js.map +1 -0
- package/lib/module/components/Button/Button.js +121 -0
- package/lib/module/components/Button/Button.js.map +1 -0
- package/lib/module/components/Button/button.types.js +4 -0
- package/lib/module/components/Button/button.types.js.map +1 -0
- package/lib/module/components/Button/button.utils.js +120 -0
- package/lib/module/components/Button/button.utils.js.map +1 -0
- package/lib/module/components/Button/index.js +5 -0
- package/lib/module/components/Button/index.js.map +1 -0
- package/lib/module/components/Skeleton/Skeleton.js +149 -0
- package/lib/module/components/Skeleton/Skeleton.js.map +1 -0
- package/lib/module/components/Skeleton/index.js +4 -0
- package/lib/module/components/Skeleton/index.js.map +1 -0
- package/lib/module/components/Skeleton/skeleton.types.js +4 -0
- package/lib/module/components/Skeleton/skeleton.types.js.map +1 -0
- package/lib/module/components/Skeleton/skeleton.utils.js +40 -0
- package/lib/module/components/Skeleton/skeleton.utils.js.map +1 -0
- package/lib/module/components/Tag/Tag.js +157 -0
- package/lib/module/components/Tag/Tag.js.map +1 -0
- package/lib/module/components/Tag/index.js +5 -0
- package/lib/module/components/Tag/index.js.map +1 -0
- package/lib/module/components/Tag/tag.types.js +4 -0
- package/lib/module/components/Tag/tag.types.js.map +1 -0
- package/lib/module/components/Tag/tag.utils.js +64 -0
- package/lib/module/components/Tag/tag.utils.js.map +1 -0
- package/lib/module/components/TextInput/TextInput.js +134 -0
- package/lib/module/components/TextInput/TextInput.js.map +1 -0
- package/lib/module/components/TextInput/index.js +4 -0
- package/lib/module/components/TextInput/index.js.map +1 -0
- package/lib/module/components/TextInput/textInput.types.js +4 -0
- package/lib/module/components/TextInput/textInput.types.js.map +1 -0
- package/lib/module/components/TextInput/textInput.utils.js +36 -0
- package/lib/module/components/TextInput/textInput.utils.js.map +1 -0
- package/lib/module/components/shared/field/FieldFooter.js +47 -0
- package/lib/module/components/shared/field/FieldFooter.js.map +1 -0
- package/lib/module/components/shared/field/FieldLabels.js +63 -0
- package/lib/module/components/shared/field/FieldLabels.js.map +1 -0
- package/lib/module/components/shared/field/fieldState.js +33 -0
- package/lib/module/components/shared/field/fieldState.js.map +1 -0
- package/lib/module/components/shared/group.js +68 -0
- package/lib/module/components/shared/group.js.map +1 -0
- package/lib/module/index.js +80 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/motion/motion.js +123 -0
- package/lib/module/motion/motion.js.map +1 -0
- package/lib/module/motion/useReduceMotion.js +33 -0
- package/lib/module/motion/useReduceMotion.js.map +1 -0
- package/lib/module/overlay/portal.js +104 -0
- package/lib/module/overlay/portal.js.map +1 -0
- package/lib/module/overlay/positioning.js +118 -0
- package/lib/module/overlay/positioning.js.map +1 -0
- package/lib/module/overlay/safeAreaInsets.js +27 -0
- package/lib/module/overlay/safeAreaInsets.js.map +1 -0
- package/lib/module/overlay/sheet/BottomSheet.js +190 -0
- package/lib/module/overlay/sheet/BottomSheet.js.map +1 -0
- package/lib/module/overlay/sheet/sheetMath.js +53 -0
- package/lib/module/overlay/sheet/sheetMath.js.map +1 -0
- package/lib/module/overlay/toast/ToastOutlet.js +101 -0
- package/lib/module/overlay/toast/ToastOutlet.js.map +1 -0
- package/lib/module/overlay/toast/toastStore.js +66 -0
- package/lib/module/overlay/toast/toastStore.js.map +1 -0
- package/lib/module/overlay/useAnchoredPosition.js +82 -0
- package/lib/module/overlay/useAnchoredPosition.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/primitives/Block.js +107 -0
- package/lib/module/primitives/Block.js.map +1 -0
- package/lib/module/primitives/Pressable.js +339 -0
- package/lib/module/primitives/Pressable.js.map +1 -0
- package/lib/module/primitives/PrimitiveInput.js +62 -0
- package/lib/module/primitives/PrimitiveInput.js.map +1 -0
- package/lib/module/primitives/Separator.js +50 -0
- package/lib/module/primitives/Separator.js.map +1 -0
- package/lib/module/primitives/Slot.js +69 -0
- package/lib/module/primitives/Slot.js.map +1 -0
- package/lib/module/primitives/Text.js +68 -0
- package/lib/module/primitives/Text.js.map +1 -0
- package/lib/module/primitives/pressFeedback.js +48 -0
- package/lib/module/primitives/pressFeedback.js.map +1 -0
- package/lib/module/primitives/textStyle.js +23 -0
- package/lib/module/primitives/textStyle.js.map +1 -0
- package/lib/module/primitives/tintSlot.js +42 -0
- package/lib/module/primitives/tintSlot.js.map +1 -0
- package/lib/module/primitives/touchTarget.js +58 -0
- package/lib/module/primitives/touchTarget.js.map +1 -0
- package/lib/module/theme/BlendNativeProvider.js +78 -0
- package/lib/module/theme/BlendNativeProvider.js.map +1 -0
- package/lib/module/theme/breakpoint.js +33 -0
- package/lib/module/theme/breakpoint.js.map +1 -0
- package/lib/module/theme/fonts.js +55 -0
- package/lib/module/theme/fonts.js.map +1 -0
- package/lib/module/theme/nativeTokenRegistry.js +40 -0
- package/lib/module/theme/nativeTokenRegistry.js.map +1 -0
- package/lib/module/theme/systemTheme.js +31 -0
- package/lib/module/theme/systemTheme.js.map +1 -0
- package/lib/module/theme/useNativeBreakpoint.js +24 -0
- package/lib/module/theme/useNativeBreakpoint.js.map +1 -0
- package/lib/module/theme/useNativeTokens.js +67 -0
- package/lib/module/theme/useNativeTokens.js.map +1 -0
- package/lib/typescript/commonjs/a11y/announcement.d.ts +26 -0
- package/lib/typescript/commonjs/a11y/announcement.d.ts.map +1 -0
- package/lib/typescript/commonjs/a11y/useLiveRegion.d.ts +17 -0
- package/lib/typescript/commonjs/a11y/useLiveRegion.d.ts.map +1 -0
- package/lib/typescript/commonjs/adapters/cssStringAdapter.d.ts +119 -0
- package/lib/typescript/commonjs/adapters/cssStringAdapter.d.ts.map +1 -0
- package/lib/typescript/commonjs/adapters/optionalGradient.d.ts +32 -0
- package/lib/typescript/commonjs/adapters/optionalGradient.d.ts.map +1 -0
- package/lib/typescript/commonjs/adapters/surfaceStyle.d.ts +75 -0
- package/lib/typescript/commonjs/adapters/surfaceStyle.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Alert/Alert.d.ts +14 -0
- package/lib/typescript/commonjs/components/Alert/Alert.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Alert/AlertActions.d.ts +13 -0
- package/lib/typescript/commonjs/components/Alert/AlertActions.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Alert/AlertClose.d.ts +22 -0
- package/lib/typescript/commonjs/components/Alert/AlertClose.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Alert/AlertText.d.ts +19 -0
- package/lib/typescript/commonjs/components/Alert/AlertText.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Alert/alert.tokens.d.ts +17 -0
- package/lib/typescript/commonjs/components/Alert/alert.tokens.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Alert/alert.types.d.ts +70 -0
- package/lib/typescript/commonjs/components/Alert/alert.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Alert/alert.utils.d.ts +58 -0
- package/lib/typescript/commonjs/components/Alert/alert.utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Alert/index.d.ts +7 -0
- package/lib/typescript/commonjs/components/Alert/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Button/Button.d.ts +22 -0
- package/lib/typescript/commonjs/components/Button/Button.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Button/button.types.d.ts +37 -0
- package/lib/typescript/commonjs/components/Button/button.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Button/button.utils.d.ts +98 -0
- package/lib/typescript/commonjs/components/Button/button.utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Button/index.d.ts +5 -0
- package/lib/typescript/commonjs/components/Button/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Skeleton/Skeleton.d.ts +7 -0
- package/lib/typescript/commonjs/components/Skeleton/Skeleton.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Skeleton/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/Skeleton/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Skeleton/skeleton.types.d.ts +25 -0
- package/lib/typescript/commonjs/components/Skeleton/skeleton.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Skeleton/skeleton.utils.d.ts +21 -0
- package/lib/typescript/commonjs/components/Skeleton/skeleton.utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Tag/Tag.d.ts +21 -0
- package/lib/typescript/commonjs/components/Tag/Tag.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Tag/index.d.ts +4 -0
- package/lib/typescript/commonjs/components/Tag/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Tag/tag.types.d.ts +56 -0
- package/lib/typescript/commonjs/components/Tag/tag.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/Tag/tag.utils.d.ts +41 -0
- package/lib/typescript/commonjs/components/Tag/tag.utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/TextInput/TextInput.d.ts +33 -0
- package/lib/typescript/commonjs/components/TextInput/TextInput.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/TextInput/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/TextInput/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/TextInput/textInput.types.d.ts +45 -0
- package/lib/typescript/commonjs/components/TextInput/textInput.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/TextInput/textInput.utils.d.ts +35 -0
- package/lib/typescript/commonjs/components/TextInput/textInput.utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/shared/field/FieldFooter.d.ts +22 -0
- package/lib/typescript/commonjs/components/shared/field/FieldFooter.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/shared/field/FieldLabels.d.ts +27 -0
- package/lib/typescript/commonjs/components/shared/field/FieldLabels.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/shared/field/fieldState.d.ts +23 -0
- package/lib/typescript/commonjs/components/shared/field/fieldState.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/shared/group.d.ts +50 -0
- package/lib/typescript/commonjs/components/shared/group.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +74 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/motion/motion.d.ts +121 -0
- package/lib/typescript/commonjs/motion/motion.d.ts.map +1 -0
- package/lib/typescript/commonjs/motion/useReduceMotion.d.ts +14 -0
- package/lib/typescript/commonjs/motion/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/commonjs/overlay/portal.d.ts +20 -0
- package/lib/typescript/commonjs/overlay/portal.d.ts.map +1 -0
- package/lib/typescript/commonjs/overlay/positioning.d.ts +65 -0
- package/lib/typescript/commonjs/overlay/positioning.d.ts.map +1 -0
- package/lib/typescript/commonjs/overlay/safeAreaInsets.d.ts +19 -0
- package/lib/typescript/commonjs/overlay/safeAreaInsets.d.ts.map +1 -0
- package/lib/typescript/commonjs/overlay/sheet/BottomSheet.d.ts +56 -0
- package/lib/typescript/commonjs/overlay/sheet/BottomSheet.d.ts.map +1 -0
- package/lib/typescript/commonjs/overlay/sheet/sheetMath.d.ts +32 -0
- package/lib/typescript/commonjs/overlay/sheet/sheetMath.d.ts.map +1 -0
- package/lib/typescript/commonjs/overlay/toast/ToastOutlet.d.ts +17 -0
- package/lib/typescript/commonjs/overlay/toast/ToastOutlet.d.ts.map +1 -0
- package/lib/typescript/commonjs/overlay/toast/toastStore.d.ts +45 -0
- package/lib/typescript/commonjs/overlay/toast/toastStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/overlay/useAnchoredPosition.d.ts +40 -0
- package/lib/typescript/commonjs/overlay/useAnchoredPosition.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/primitives/Block.d.ts +37 -0
- package/lib/typescript/commonjs/primitives/Block.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/Pressable.d.ts +135 -0
- package/lib/typescript/commonjs/primitives/Pressable.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/PrimitiveInput.d.ts +42 -0
- package/lib/typescript/commonjs/primitives/PrimitiveInput.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/Separator.d.ts +28 -0
- package/lib/typescript/commonjs/primitives/Separator.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/Slot.d.ts +48 -0
- package/lib/typescript/commonjs/primitives/Slot.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/Text.d.ts +50 -0
- package/lib/typescript/commonjs/primitives/Text.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/pressFeedback.d.ts +39 -0
- package/lib/typescript/commonjs/primitives/pressFeedback.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/textStyle.d.ts +13 -0
- package/lib/typescript/commonjs/primitives/textStyle.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/tintSlot.d.ts +10 -0
- package/lib/typescript/commonjs/primitives/tintSlot.d.ts.map +1 -0
- package/lib/typescript/commonjs/primitives/touchTarget.d.ts +43 -0
- package/lib/typescript/commonjs/primitives/touchTarget.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme/BlendNativeProvider.d.ts +69 -0
- package/lib/typescript/commonjs/theme/BlendNativeProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme/breakpoint.d.ts +27 -0
- package/lib/typescript/commonjs/theme/breakpoint.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme/fonts.d.ts +34 -0
- package/lib/typescript/commonjs/theme/fonts.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme/nativeTokenRegistry.d.ts +34 -0
- package/lib/typescript/commonjs/theme/nativeTokenRegistry.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme/systemTheme.d.ts +25 -0
- package/lib/typescript/commonjs/theme/systemTheme.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme/useNativeBreakpoint.d.ts +17 -0
- package/lib/typescript/commonjs/theme/useNativeBreakpoint.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme/useNativeTokens.d.ts +4 -0
- package/lib/typescript/commonjs/theme/useNativeTokens.d.ts.map +1 -0
- package/lib/typescript/module/a11y/announcement.d.ts +26 -0
- package/lib/typescript/module/a11y/announcement.d.ts.map +1 -0
- package/lib/typescript/module/a11y/useLiveRegion.d.ts +17 -0
- package/lib/typescript/module/a11y/useLiveRegion.d.ts.map +1 -0
- package/lib/typescript/module/adapters/cssStringAdapter.d.ts +119 -0
- package/lib/typescript/module/adapters/cssStringAdapter.d.ts.map +1 -0
- package/lib/typescript/module/adapters/optionalGradient.d.ts +32 -0
- package/lib/typescript/module/adapters/optionalGradient.d.ts.map +1 -0
- package/lib/typescript/module/adapters/surfaceStyle.d.ts +75 -0
- package/lib/typescript/module/adapters/surfaceStyle.d.ts.map +1 -0
- package/lib/typescript/module/components/Alert/Alert.d.ts +14 -0
- package/lib/typescript/module/components/Alert/Alert.d.ts.map +1 -0
- package/lib/typescript/module/components/Alert/AlertActions.d.ts +13 -0
- package/lib/typescript/module/components/Alert/AlertActions.d.ts.map +1 -0
- package/lib/typescript/module/components/Alert/AlertClose.d.ts +22 -0
- package/lib/typescript/module/components/Alert/AlertClose.d.ts.map +1 -0
- package/lib/typescript/module/components/Alert/AlertText.d.ts +19 -0
- package/lib/typescript/module/components/Alert/AlertText.d.ts.map +1 -0
- package/lib/typescript/module/components/Alert/alert.tokens.d.ts +17 -0
- package/lib/typescript/module/components/Alert/alert.tokens.d.ts.map +1 -0
- package/lib/typescript/module/components/Alert/alert.types.d.ts +70 -0
- package/lib/typescript/module/components/Alert/alert.types.d.ts.map +1 -0
- package/lib/typescript/module/components/Alert/alert.utils.d.ts +58 -0
- package/lib/typescript/module/components/Alert/alert.utils.d.ts.map +1 -0
- package/lib/typescript/module/components/Alert/index.d.ts +7 -0
- package/lib/typescript/module/components/Alert/index.d.ts.map +1 -0
- package/lib/typescript/module/components/Button/Button.d.ts +22 -0
- package/lib/typescript/module/components/Button/Button.d.ts.map +1 -0
- package/lib/typescript/module/components/Button/button.types.d.ts +37 -0
- package/lib/typescript/module/components/Button/button.types.d.ts.map +1 -0
- package/lib/typescript/module/components/Button/button.utils.d.ts +98 -0
- package/lib/typescript/module/components/Button/button.utils.d.ts.map +1 -0
- package/lib/typescript/module/components/Button/index.d.ts +5 -0
- package/lib/typescript/module/components/Button/index.d.ts.map +1 -0
- package/lib/typescript/module/components/Skeleton/Skeleton.d.ts +7 -0
- package/lib/typescript/module/components/Skeleton/Skeleton.d.ts.map +1 -0
- package/lib/typescript/module/components/Skeleton/index.d.ts +3 -0
- package/lib/typescript/module/components/Skeleton/index.d.ts.map +1 -0
- package/lib/typescript/module/components/Skeleton/skeleton.types.d.ts +25 -0
- package/lib/typescript/module/components/Skeleton/skeleton.types.d.ts.map +1 -0
- package/lib/typescript/module/components/Skeleton/skeleton.utils.d.ts +21 -0
- package/lib/typescript/module/components/Skeleton/skeleton.utils.d.ts.map +1 -0
- package/lib/typescript/module/components/Tag/Tag.d.ts +21 -0
- package/lib/typescript/module/components/Tag/Tag.d.ts.map +1 -0
- package/lib/typescript/module/components/Tag/index.d.ts +4 -0
- package/lib/typescript/module/components/Tag/index.d.ts.map +1 -0
- package/lib/typescript/module/components/Tag/tag.types.d.ts +56 -0
- package/lib/typescript/module/components/Tag/tag.types.d.ts.map +1 -0
- package/lib/typescript/module/components/Tag/tag.utils.d.ts +41 -0
- package/lib/typescript/module/components/Tag/tag.utils.d.ts.map +1 -0
- package/lib/typescript/module/components/TextInput/TextInput.d.ts +33 -0
- package/lib/typescript/module/components/TextInput/TextInput.d.ts.map +1 -0
- package/lib/typescript/module/components/TextInput/index.d.ts +3 -0
- package/lib/typescript/module/components/TextInput/index.d.ts.map +1 -0
- package/lib/typescript/module/components/TextInput/textInput.types.d.ts +45 -0
- package/lib/typescript/module/components/TextInput/textInput.types.d.ts.map +1 -0
- package/lib/typescript/module/components/TextInput/textInput.utils.d.ts +35 -0
- package/lib/typescript/module/components/TextInput/textInput.utils.d.ts.map +1 -0
- package/lib/typescript/module/components/shared/field/FieldFooter.d.ts +22 -0
- package/lib/typescript/module/components/shared/field/FieldFooter.d.ts.map +1 -0
- package/lib/typescript/module/components/shared/field/FieldLabels.d.ts +27 -0
- package/lib/typescript/module/components/shared/field/FieldLabels.d.ts.map +1 -0
- package/lib/typescript/module/components/shared/field/fieldState.d.ts +23 -0
- package/lib/typescript/module/components/shared/field/fieldState.d.ts.map +1 -0
- package/lib/typescript/module/components/shared/group.d.ts +50 -0
- package/lib/typescript/module/components/shared/group.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +74 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/motion/motion.d.ts +121 -0
- package/lib/typescript/module/motion/motion.d.ts.map +1 -0
- package/lib/typescript/module/motion/useReduceMotion.d.ts +14 -0
- package/lib/typescript/module/motion/useReduceMotion.d.ts.map +1 -0
- package/lib/typescript/module/overlay/portal.d.ts +20 -0
- package/lib/typescript/module/overlay/portal.d.ts.map +1 -0
- package/lib/typescript/module/overlay/positioning.d.ts +65 -0
- package/lib/typescript/module/overlay/positioning.d.ts.map +1 -0
- package/lib/typescript/module/overlay/safeAreaInsets.d.ts +19 -0
- package/lib/typescript/module/overlay/safeAreaInsets.d.ts.map +1 -0
- package/lib/typescript/module/overlay/sheet/BottomSheet.d.ts +56 -0
- package/lib/typescript/module/overlay/sheet/BottomSheet.d.ts.map +1 -0
- package/lib/typescript/module/overlay/sheet/sheetMath.d.ts +32 -0
- package/lib/typescript/module/overlay/sheet/sheetMath.d.ts.map +1 -0
- package/lib/typescript/module/overlay/toast/ToastOutlet.d.ts +17 -0
- package/lib/typescript/module/overlay/toast/ToastOutlet.d.ts.map +1 -0
- package/lib/typescript/module/overlay/toast/toastStore.d.ts +45 -0
- package/lib/typescript/module/overlay/toast/toastStore.d.ts.map +1 -0
- package/lib/typescript/module/overlay/useAnchoredPosition.d.ts +40 -0
- package/lib/typescript/module/overlay/useAnchoredPosition.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/primitives/Block.d.ts +37 -0
- package/lib/typescript/module/primitives/Block.d.ts.map +1 -0
- package/lib/typescript/module/primitives/Pressable.d.ts +135 -0
- package/lib/typescript/module/primitives/Pressable.d.ts.map +1 -0
- package/lib/typescript/module/primitives/PrimitiveInput.d.ts +42 -0
- package/lib/typescript/module/primitives/PrimitiveInput.d.ts.map +1 -0
- package/lib/typescript/module/primitives/Separator.d.ts +28 -0
- package/lib/typescript/module/primitives/Separator.d.ts.map +1 -0
- package/lib/typescript/module/primitives/Slot.d.ts +48 -0
- package/lib/typescript/module/primitives/Slot.d.ts.map +1 -0
- package/lib/typescript/module/primitives/Text.d.ts +50 -0
- package/lib/typescript/module/primitives/Text.d.ts.map +1 -0
- package/lib/typescript/module/primitives/pressFeedback.d.ts +39 -0
- package/lib/typescript/module/primitives/pressFeedback.d.ts.map +1 -0
- package/lib/typescript/module/primitives/textStyle.d.ts +13 -0
- package/lib/typescript/module/primitives/textStyle.d.ts.map +1 -0
- package/lib/typescript/module/primitives/tintSlot.d.ts +10 -0
- package/lib/typescript/module/primitives/tintSlot.d.ts.map +1 -0
- package/lib/typescript/module/primitives/touchTarget.d.ts +43 -0
- package/lib/typescript/module/primitives/touchTarget.d.ts.map +1 -0
- package/lib/typescript/module/theme/BlendNativeProvider.d.ts +69 -0
- package/lib/typescript/module/theme/BlendNativeProvider.d.ts.map +1 -0
- package/lib/typescript/module/theme/breakpoint.d.ts +27 -0
- package/lib/typescript/module/theme/breakpoint.d.ts.map +1 -0
- package/lib/typescript/module/theme/fonts.d.ts +34 -0
- package/lib/typescript/module/theme/fonts.d.ts.map +1 -0
- package/lib/typescript/module/theme/nativeTokenRegistry.d.ts +34 -0
- package/lib/typescript/module/theme/nativeTokenRegistry.d.ts.map +1 -0
- package/lib/typescript/module/theme/systemTheme.d.ts +25 -0
- package/lib/typescript/module/theme/systemTheme.d.ts.map +1 -0
- package/lib/typescript/module/theme/useNativeBreakpoint.d.ts +17 -0
- package/lib/typescript/module/theme/useNativeBreakpoint.d.ts.map +1 -0
- package/lib/typescript/module/theme/useNativeTokens.d.ts +4 -0
- package/lib/typescript/module/theme/useNativeTokens.d.ts.map +1 -0
- package/package.json +137 -0
- package/src/a11y/announcement.ts +41 -0
- package/src/a11y/useLiveRegion.ts +36 -0
- package/src/adapters/cssStringAdapter.ts +403 -0
- package/src/adapters/optionalGradient.ts +39 -0
- package/src/adapters/surfaceStyle.ts +209 -0
- package/src/components/Alert/Alert.tsx +167 -0
- package/src/components/Alert/AlertActions.tsx +98 -0
- package/src/components/Alert/AlertClose.tsx +53 -0
- package/src/components/Alert/AlertText.tsx +58 -0
- package/src/components/Alert/alert.tokens.ts +24 -0
- package/src/components/Alert/alert.types.ts +81 -0
- package/src/components/Alert/alert.utils.ts +94 -0
- package/src/components/Alert/index.ts +21 -0
- package/src/components/Button/Button.tsx +180 -0
- package/src/components/Button/button.types.ts +44 -0
- package/src/components/Button/button.utils.ts +213 -0
- package/src/components/Button/index.ts +12 -0
- package/src/components/Skeleton/Skeleton.tsx +196 -0
- package/src/components/Skeleton/index.ts +2 -0
- package/src/components/Skeleton/skeleton.types.ts +28 -0
- package/src/components/Skeleton/skeleton.utils.ts +56 -0
- package/src/components/Tag/Tag.tsx +204 -0
- package/src/components/Tag/index.ts +7 -0
- package/src/components/Tag/tag.types.ts +63 -0
- package/src/components/Tag/tag.utils.ts +82 -0
- package/src/components/TextInput/TextInput.tsx +165 -0
- package/src/components/TextInput/index.ts +2 -0
- package/src/components/TextInput/textInput.types.ts +54 -0
- package/src/components/TextInput/textInput.utils.ts +68 -0
- package/src/components/shared/field/FieldFooter.tsx +66 -0
- package/src/components/shared/field/FieldLabels.tsx +86 -0
- package/src/components/shared/field/fieldState.ts +39 -0
- package/src/components/shared/group.ts +72 -0
- package/src/index.ts +144 -0
- package/src/motion/motion.ts +115 -0
- package/src/motion/useReduceMotion.ts +36 -0
- package/src/overlay/portal.tsx +122 -0
- package/src/overlay/positioning.ts +196 -0
- package/src/overlay/safeAreaInsets.ts +36 -0
- package/src/overlay/sheet/BottomSheet.tsx +276 -0
- package/src/overlay/sheet/sheetMath.ts +58 -0
- package/src/overlay/toast/ToastOutlet.tsx +127 -0
- package/src/overlay/toast/toastStore.ts +96 -0
- package/src/overlay/useAnchoredPosition.ts +92 -0
- package/src/primitives/Block.tsx +129 -0
- package/src/primitives/Pressable.tsx +528 -0
- package/src/primitives/PrimitiveInput.tsx +87 -0
- package/src/primitives/Separator.tsx +65 -0
- package/src/primitives/Slot.tsx +94 -0
- package/src/primitives/Text.tsx +98 -0
- package/src/primitives/pressFeedback.ts +78 -0
- package/src/primitives/textStyle.ts +24 -0
- package/src/primitives/tintSlot.ts +44 -0
- package/src/primitives/touchTarget.ts +72 -0
- package/src/theme/BlendNativeProvider.tsx +147 -0
- package/src/theme/breakpoint.ts +38 -0
- package/src/theme/fonts.ts +63 -0
- package/src/theme/nativeTokenRegistry.ts +57 -0
- package/src/theme/systemTheme.ts +34 -0
- package/src/theme/useNativeBreakpoint.ts +27 -0
- package/src/theme/useNativeTokens.ts +99 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useId,
|
|
7
|
+
useMemo,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react'
|
|
10
|
+
import { StyleSheet, View } from 'react-native'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Portal — layered rendering above the app's content.
|
|
14
|
+
*
|
|
15
|
+
* The native replacement for web's `createPortal`/Radix `Portal`: overlay
|
|
16
|
+
* components (modal, menu, popover, tooltip, snackbar) mount their surface
|
|
17
|
+
* through `<Portal>` and it renders in an absolute-fill layer that
|
|
18
|
+
* `BlendNativeProvider` places *after* the app's children, so it paints on
|
|
19
|
+
* top regardless of where in the tree the overlay was opened.
|
|
20
|
+
*
|
|
21
|
+
* Layers stack in mount order — the overlay opened last paints on top,
|
|
22
|
+
* which matches how web portals appended to `document.body` behave.
|
|
23
|
+
*
|
|
24
|
+
* The provider must sit at a screen-filling root (the usual place for a
|
|
25
|
+
* theme provider): the layers are absolutely positioned siblings of the
|
|
26
|
+
* app's children, so they cover exactly what the provider's parent covers.
|
|
27
|
+
*
|
|
28
|
+
* With no provider mounted, `<Portal>` renders its children in place — an
|
|
29
|
+
* overlay degrades to inline rendering rather than disappearing.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
type PortalNode = { key: string; node: React.ReactNode }
|
|
33
|
+
|
|
34
|
+
type PortalRegistry = {
|
|
35
|
+
mount: (key: string, node: React.ReactNode) => void
|
|
36
|
+
unmount: (key: string) => void
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const PortalRegistryContext = createContext<PortalRegistry | null>(null)
|
|
40
|
+
|
|
41
|
+
let warnedNoProvider = false
|
|
42
|
+
|
|
43
|
+
export type PortalProps = { children?: React.ReactNode }
|
|
44
|
+
|
|
45
|
+
/** Renders `children` into the provider's overlay layer. */
|
|
46
|
+
export function Portal({ children }: PortalProps) {
|
|
47
|
+
const registry = useContext(PortalRegistryContext)
|
|
48
|
+
const key = useId()
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!registry) return
|
|
52
|
+
registry.mount(key, children)
|
|
53
|
+
return () => registry.unmount(key)
|
|
54
|
+
}, [registry, key, children])
|
|
55
|
+
|
|
56
|
+
// In an effect, not during render — warning inline would be a
|
|
57
|
+
// render-phase side effect (breaks under StrictMode double-render, the
|
|
58
|
+
// same class of bug Pressable's parse memoisation fixed).
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (registry || warnedNoProvider) return
|
|
61
|
+
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
62
|
+
warnedNoProvider = true
|
|
63
|
+
console.warn(
|
|
64
|
+
'[blend-native] <Portal> used without BlendNativeProvider — ' +
|
|
65
|
+
'rendering inline. Overlays will not layer above the app.'
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
}, [registry])
|
|
69
|
+
|
|
70
|
+
if (!registry) return <>{children}</>
|
|
71
|
+
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Portal.displayName = 'Portal'
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Internal — wraps the app's children with the portal registry and renders
|
|
79
|
+
* the mounted layers after them. Used by `BlendNativeProvider`; not public.
|
|
80
|
+
*/
|
|
81
|
+
export function PortalArea({ children }: { children?: React.ReactNode }) {
|
|
82
|
+
const [portals, setPortals] = useState<PortalNode[]>([])
|
|
83
|
+
|
|
84
|
+
const mount = useCallback((key: string, node: React.ReactNode) => {
|
|
85
|
+
setPortals((current) => {
|
|
86
|
+
const existing = current.findIndex((p) => p.key === key)
|
|
87
|
+
if (existing === -1) return [...current, { key, node }]
|
|
88
|
+
// Re-mount with new content keeps its layer position.
|
|
89
|
+
const next = current.slice()
|
|
90
|
+
next[existing] = { key, node }
|
|
91
|
+
return next
|
|
92
|
+
})
|
|
93
|
+
}, [])
|
|
94
|
+
|
|
95
|
+
const unmount = useCallback((key: string) => {
|
|
96
|
+
setPortals((current) => current.filter((p) => p.key !== key))
|
|
97
|
+
}, [])
|
|
98
|
+
|
|
99
|
+
const registry = useMemo<PortalRegistry>(
|
|
100
|
+
() => ({ mount, unmount }),
|
|
101
|
+
[mount, unmount]
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<PortalRegistryContext.Provider value={registry}>
|
|
106
|
+
{children}
|
|
107
|
+
{portals.map(({ key, node }) => (
|
|
108
|
+
<View
|
|
109
|
+
key={key}
|
|
110
|
+
style={StyleSheet.absoluteFill}
|
|
111
|
+
// Touches fall through empty layer area to the app;
|
|
112
|
+
// the overlay's own views still receive theirs.
|
|
113
|
+
pointerEvents="box-none"
|
|
114
|
+
>
|
|
115
|
+
{node}
|
|
116
|
+
</View>
|
|
117
|
+
))}
|
|
118
|
+
</PortalRegistryContext.Provider>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
PortalArea.displayName = 'PortalArea'
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchored-overlay positioning.
|
|
3
|
+
*
|
|
4
|
+
* The native replacement for what Radix/floating-ui do on web: place a
|
|
5
|
+
* floating box (menu, popover, tooltip, select list) against an anchor
|
|
6
|
+
* rect, flipping to the opposite side when space runs out and clamping
|
|
7
|
+
* into the viewport.
|
|
8
|
+
*
|
|
9
|
+
* Pure and RN-free — rects in, a position out — so the whole placement
|
|
10
|
+
* matrix is unit-testable under vitest. `useAnchoredPosition` layers the
|
|
11
|
+
* measurement plumbing on top.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type Rect = { x: number; y: number; width: number; height: number }
|
|
15
|
+
export type Size = { width: number; height: number }
|
|
16
|
+
|
|
17
|
+
/** Which side of the anchor the content prefers. */
|
|
18
|
+
export type Placement = 'top' | 'bottom' | 'left' | 'right'
|
|
19
|
+
|
|
20
|
+
/** Alignment along the anchor's other axis. */
|
|
21
|
+
export type Alignment = 'start' | 'center' | 'end'
|
|
22
|
+
|
|
23
|
+
export type AnchoredPositionInput = {
|
|
24
|
+
/** The anchor's rect in window coordinates (`measureInWindow`). */
|
|
25
|
+
anchor: Rect
|
|
26
|
+
/** The floating content's measured size. */
|
|
27
|
+
content: Size
|
|
28
|
+
/** The window size (`useWindowDimensions`). */
|
|
29
|
+
viewport: Size
|
|
30
|
+
placement?: Placement
|
|
31
|
+
alignment?: Alignment
|
|
32
|
+
/** Gap between anchor and content, in points. */
|
|
33
|
+
offset?: number
|
|
34
|
+
/** Minimum distance kept from every viewport edge, in points. */
|
|
35
|
+
viewportPadding?: number
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type AnchoredPosition = {
|
|
39
|
+
x: number
|
|
40
|
+
y: number
|
|
41
|
+
/** The placement actually used, after any flip. */
|
|
42
|
+
placement: Placement
|
|
43
|
+
/**
|
|
44
|
+
* Space available for the content on the resolved side, after padding.
|
|
45
|
+
* Callers cap scrollable content (menus, select lists) with these so a
|
|
46
|
+
* long list scrolls instead of overflowing the screen.
|
|
47
|
+
*/
|
|
48
|
+
maxHeight: number
|
|
49
|
+
maxWidth: number
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const opposite: Record<Placement, Placement> = {
|
|
53
|
+
top: 'bottom',
|
|
54
|
+
bottom: 'top',
|
|
55
|
+
left: 'right',
|
|
56
|
+
right: 'left',
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Space between the anchor and the viewport edge on one side. */
|
|
60
|
+
function spaceOn(
|
|
61
|
+
side: Placement,
|
|
62
|
+
anchor: Rect,
|
|
63
|
+
viewport: Size,
|
|
64
|
+
offset: number,
|
|
65
|
+
padding: number
|
|
66
|
+
): number {
|
|
67
|
+
switch (side) {
|
|
68
|
+
case 'top':
|
|
69
|
+
return anchor.y - offset - padding
|
|
70
|
+
case 'bottom':
|
|
71
|
+
return (
|
|
72
|
+
viewport.height - (anchor.y + anchor.height) - offset - padding
|
|
73
|
+
)
|
|
74
|
+
case 'left':
|
|
75
|
+
return anchor.x - offset - padding
|
|
76
|
+
case 'right':
|
|
77
|
+
return viewport.width - (anchor.x + anchor.width) - offset - padding
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const clamp = (value: number, min: number, max: number) =>
|
|
82
|
+
// A viewport smaller than the padding produces min > max; the lower
|
|
83
|
+
// bound wins so content pins to the leading edge instead of NaN-ing.
|
|
84
|
+
Math.max(min, Math.min(value, Math.max(min, max)))
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Compute where to place floating content against an anchor.
|
|
88
|
+
*
|
|
89
|
+
* - **Flip**: when the preferred side cannot fit the content but the
|
|
90
|
+
* opposite side can fit more of it, the placement flips.
|
|
91
|
+
* - **Clamp**: the cross-axis position shifts to keep the content inside
|
|
92
|
+
* the viewport padding (matching floating-ui's `shift`).
|
|
93
|
+
* - **Cap**: `maxHeight`/`maxWidth` report the space actually available on
|
|
94
|
+
* the resolved side, so scrollable content can cap itself.
|
|
95
|
+
*/
|
|
96
|
+
export function computeAnchoredPosition(
|
|
97
|
+
input: AnchoredPositionInput
|
|
98
|
+
): AnchoredPosition {
|
|
99
|
+
const {
|
|
100
|
+
anchor,
|
|
101
|
+
content,
|
|
102
|
+
viewport,
|
|
103
|
+
placement: preferred = 'bottom',
|
|
104
|
+
alignment = 'start',
|
|
105
|
+
offset = 8,
|
|
106
|
+
viewportPadding = 8,
|
|
107
|
+
} = input
|
|
108
|
+
|
|
109
|
+
const preferredSpace = spaceOn(
|
|
110
|
+
preferred,
|
|
111
|
+
anchor,
|
|
112
|
+
viewport,
|
|
113
|
+
offset,
|
|
114
|
+
viewportPadding
|
|
115
|
+
)
|
|
116
|
+
const isVertical = preferred === 'top' || preferred === 'bottom'
|
|
117
|
+
const needed = isVertical ? content.height : content.width
|
|
118
|
+
|
|
119
|
+
let placement = preferred
|
|
120
|
+
if (needed > preferredSpace) {
|
|
121
|
+
const other = spaceOn(
|
|
122
|
+
opposite[preferred],
|
|
123
|
+
anchor,
|
|
124
|
+
viewport,
|
|
125
|
+
offset,
|
|
126
|
+
viewportPadding
|
|
127
|
+
)
|
|
128
|
+
if (other > preferredSpace) placement = opposite[preferred]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ---- Main axis ------------------------------------------------------
|
|
132
|
+
let x = 0
|
|
133
|
+
let y = 0
|
|
134
|
+
switch (placement) {
|
|
135
|
+
case 'top':
|
|
136
|
+
y = anchor.y - offset - content.height
|
|
137
|
+
break
|
|
138
|
+
case 'bottom':
|
|
139
|
+
y = anchor.y + anchor.height + offset
|
|
140
|
+
break
|
|
141
|
+
case 'left':
|
|
142
|
+
x = anchor.x - offset - content.width
|
|
143
|
+
break
|
|
144
|
+
case 'right':
|
|
145
|
+
x = anchor.x + anchor.width + offset
|
|
146
|
+
break
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ---- Cross axis -----------------------------------------------------
|
|
150
|
+
const alignAlong = (
|
|
151
|
+
anchorStart: number,
|
|
152
|
+
anchorLength: number,
|
|
153
|
+
contentLength: number
|
|
154
|
+
) => {
|
|
155
|
+
if (alignment === 'start') return anchorStart
|
|
156
|
+
if (alignment === 'end')
|
|
157
|
+
return anchorStart + anchorLength - contentLength
|
|
158
|
+
return anchorStart + (anchorLength - contentLength) / 2
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (placement === 'top' || placement === 'bottom') {
|
|
162
|
+
x = alignAlong(anchor.x, anchor.width, content.width)
|
|
163
|
+
} else {
|
|
164
|
+
y = alignAlong(anchor.y, anchor.height, content.height)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ---- Keep inside the viewport ---------------------------------------
|
|
168
|
+
x = clamp(
|
|
169
|
+
x,
|
|
170
|
+
viewportPadding,
|
|
171
|
+
viewport.width - viewportPadding - content.width
|
|
172
|
+
)
|
|
173
|
+
y = clamp(
|
|
174
|
+
y,
|
|
175
|
+
viewportPadding,
|
|
176
|
+
viewport.height - viewportPadding - content.height
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
const available = spaceOn(
|
|
180
|
+
placement,
|
|
181
|
+
anchor,
|
|
182
|
+
viewport,
|
|
183
|
+
offset,
|
|
184
|
+
viewportPadding
|
|
185
|
+
)
|
|
186
|
+
const maxHeight =
|
|
187
|
+
placement === 'top' || placement === 'bottom'
|
|
188
|
+
? Math.max(0, available)
|
|
189
|
+
: Math.max(0, viewport.height - 2 * viewportPadding)
|
|
190
|
+
const maxWidth =
|
|
191
|
+
placement === 'left' || placement === 'right'
|
|
192
|
+
? Math.max(0, available)
|
|
193
|
+
: Math.max(0, viewport.width - 2 * viewportPadding)
|
|
194
|
+
|
|
195
|
+
return { x, y, placement, maxHeight, maxWidth }
|
|
196
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React, { createContext } from 'react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Optional `react-native-safe-area-context` integration, shared by every
|
|
5
|
+
* overlay that must respect the home indicator or notch (BottomSheet, the
|
|
6
|
+
* toast outlet).
|
|
7
|
+
*
|
|
8
|
+
* `useContext` needs *a* context unconditionally, so when the optional peer
|
|
9
|
+
* is absent — or its provider is not mounted — a null-valued fallback
|
|
10
|
+
* stands in and insets resolve to zero. Same probe pattern as
|
|
11
|
+
* expo-linear-gradient.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type EdgeInsets = {
|
|
15
|
+
top: number
|
|
16
|
+
bottom: number
|
|
17
|
+
left: number
|
|
18
|
+
right: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const FallbackInsetsContext = createContext<EdgeInsets | null>(null)
|
|
22
|
+
|
|
23
|
+
export let SafeAreaInsetsContext: React.Context<EdgeInsets | null> =
|
|
24
|
+
FallbackInsetsContext
|
|
25
|
+
try {
|
|
26
|
+
if (typeof require === 'function') {
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
28
|
+
const safeArea = require('react-native-safe-area-context') as {
|
|
29
|
+
SafeAreaInsetsContext?: React.Context<EdgeInsets | null>
|
|
30
|
+
}
|
|
31
|
+
SafeAreaInsetsContext =
|
|
32
|
+
safeArea.SafeAreaInsetsContext ?? FallbackInsetsContext
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
SafeAreaInsetsContext = FallbackInsetsContext
|
|
36
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import React, { useCallback, useContext, useEffect, useState } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
BackHandler,
|
|
4
|
+
Pressable,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
useWindowDimensions,
|
|
7
|
+
View,
|
|
8
|
+
type LayoutChangeEvent,
|
|
9
|
+
type ViewStyle,
|
|
10
|
+
} from 'react-native'
|
|
11
|
+
import Animated, {
|
|
12
|
+
Easing,
|
|
13
|
+
runOnJS,
|
|
14
|
+
useAnimatedStyle,
|
|
15
|
+
useSharedValue,
|
|
16
|
+
withSpring,
|
|
17
|
+
withTiming,
|
|
18
|
+
} from 'react-native-reanimated'
|
|
19
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
|
|
20
|
+
import { Portal } from '../portal'
|
|
21
|
+
import { SafeAreaInsetsContext } from '../safeAreaInsets'
|
|
22
|
+
import { MOTION_DURATION, MOTION_EASING } from '../../motion/motion'
|
|
23
|
+
import { useReduceMotion } from '../../motion/useReduceMotion'
|
|
24
|
+
import {
|
|
25
|
+
clampSheetDrag,
|
|
26
|
+
resolveSheetMaxHeight,
|
|
27
|
+
shouldDismissSheet,
|
|
28
|
+
SHEET_MAX_HEIGHT_FRACTION,
|
|
29
|
+
} from './sheetMath'
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* BottomSheet — the gesture-driven sheet foundation.
|
|
33
|
+
*
|
|
34
|
+
* The native replacement for `vaul` and the phone presentation web already
|
|
35
|
+
* prescribes in its Mobile* variants (mobileModalV2, MobileSingleSelectV2,
|
|
36
|
+
* MobilePopoverV2): DrawerV2 and the phone modes of Select/Menu/Modal
|
|
37
|
+
* compose this primitive and pass their token values in — the sheet itself
|
|
38
|
+
* carries structure and physics, not design decisions, which is why its
|
|
39
|
+
* colour props have plain defaults instead of token lookups.
|
|
40
|
+
*
|
|
41
|
+
* Controlled: `open` drives it; every dismiss route (drag, backdrop, the
|
|
42
|
+
* Android back button) calls `onClose` and the owner flips `open` — the
|
|
43
|
+
* exit animation runs, then the sheet unmounts from the portal layer.
|
|
44
|
+
*
|
|
45
|
+
* Requirements: `react-native-reanimated` and `react-native-gesture-handler`
|
|
46
|
+
* (required peers), and a `GestureHandlerRootView` at the app root — apps
|
|
47
|
+
* using react-navigation already have one. `react-native-safe-area-context`
|
|
48
|
+
* is optional: with it (and its provider) mounted, the sheet pads itself
|
|
49
|
+
* past the home indicator; without it the bottom inset is 0.
|
|
50
|
+
*
|
|
51
|
+
* Reduce-motion: the slide collapses to a fade (`useReduceMotion`).
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
export type BottomSheetProps = {
|
|
55
|
+
/** Whether the sheet is presented. */
|
|
56
|
+
open: boolean
|
|
57
|
+
/** Called whenever the sheet asks to close; the owner flips `open`. */
|
|
58
|
+
onClose: () => void
|
|
59
|
+
children?: React.ReactNode
|
|
60
|
+
/** Cap on sheet height as a fraction of the window. Default 0.9. */
|
|
61
|
+
maxHeightFraction?: number
|
|
62
|
+
/** Backdrop fill. Defaults to 50% black. */
|
|
63
|
+
backdropColor?: string
|
|
64
|
+
/** Sheet surface colour. Component layers pass their token value. */
|
|
65
|
+
backgroundColor?: string
|
|
66
|
+
/** Radius of the two top corners. */
|
|
67
|
+
topRadius?: number
|
|
68
|
+
/** Show the drag handle. Default true. */
|
|
69
|
+
showHandle?: boolean
|
|
70
|
+
handleColor?: string
|
|
71
|
+
/** Allow drag-down to dismiss. Default true. */
|
|
72
|
+
dragToDismiss?: boolean
|
|
73
|
+
/** Dismiss when the backdrop is pressed. Default true. */
|
|
74
|
+
dismissOnBackdropPress?: boolean
|
|
75
|
+
accessibilityLabel?: string
|
|
76
|
+
testID?: string
|
|
77
|
+
/** Style escape hatch for the sheet surface. */
|
|
78
|
+
style?: ViewStyle
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const ENTER = {
|
|
82
|
+
duration: MOTION_DURATION.slow,
|
|
83
|
+
easing: Easing.bezier(...MOTION_EASING.decelerate),
|
|
84
|
+
}
|
|
85
|
+
const EXIT = {
|
|
86
|
+
duration: MOTION_DURATION.normal,
|
|
87
|
+
easing: Easing.bezier(...MOTION_EASING.accelerate),
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function BottomSheet({
|
|
91
|
+
open,
|
|
92
|
+
onClose,
|
|
93
|
+
children,
|
|
94
|
+
maxHeightFraction = SHEET_MAX_HEIGHT_FRACTION,
|
|
95
|
+
backdropColor = 'rgba(0, 0, 0, 0.5)',
|
|
96
|
+
backgroundColor = '#FFFFFF',
|
|
97
|
+
topRadius = 16,
|
|
98
|
+
showHandle = true,
|
|
99
|
+
handleColor = 'rgba(0, 0, 0, 0.2)',
|
|
100
|
+
dragToDismiss = true,
|
|
101
|
+
dismissOnBackdropPress = true,
|
|
102
|
+
accessibilityLabel,
|
|
103
|
+
testID,
|
|
104
|
+
style,
|
|
105
|
+
}: BottomSheetProps) {
|
|
106
|
+
// Mounted outlives `open` by one exit animation.
|
|
107
|
+
const [mounted, setMounted] = useState(open)
|
|
108
|
+
const progress = useSharedValue(0)
|
|
109
|
+
const dragY = useSharedValue(0)
|
|
110
|
+
const sheetHeight = useSharedValue(0)
|
|
111
|
+
const window = useWindowDimensions()
|
|
112
|
+
const insets = useContext(SafeAreaInsetsContext)
|
|
113
|
+
const reduceMotion = useReduceMotion()
|
|
114
|
+
|
|
115
|
+
const unmount = useCallback(() => setMounted(false), [])
|
|
116
|
+
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (open) {
|
|
119
|
+
setMounted(true)
|
|
120
|
+
progress.value = withTiming(1, ENTER)
|
|
121
|
+
} else {
|
|
122
|
+
// Drag offset folds into the exit so a gesture-dismissed sheet
|
|
123
|
+
// continues downward from wherever the finger left it.
|
|
124
|
+
dragY.value = withTiming(0, EXIT)
|
|
125
|
+
progress.value = withTiming(0, EXIT, (finished) => {
|
|
126
|
+
if (finished) runOnJS(unmount)()
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
}, [open, progress, dragY, unmount])
|
|
130
|
+
|
|
131
|
+
// Android hardware back closes the sheet instead of the screen.
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
if (!open) return
|
|
134
|
+
const subscription = BackHandler.addEventListener(
|
|
135
|
+
'hardwareBackPress',
|
|
136
|
+
() => {
|
|
137
|
+
onClose()
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
return () => subscription.remove()
|
|
142
|
+
}, [open, onClose])
|
|
143
|
+
|
|
144
|
+
const onSheetLayout = useCallback(
|
|
145
|
+
(event: LayoutChangeEvent) => {
|
|
146
|
+
sheetHeight.value = event.nativeEvent.layout.height
|
|
147
|
+
},
|
|
148
|
+
[sheetHeight]
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
const pan = Gesture.Pan()
|
|
152
|
+
.enabled(dragToDismiss)
|
|
153
|
+
.onChange((event) => {
|
|
154
|
+
dragY.value = clampSheetDrag(event.translationY)
|
|
155
|
+
})
|
|
156
|
+
.onEnd((event) => {
|
|
157
|
+
if (
|
|
158
|
+
shouldDismissSheet(
|
|
159
|
+
event.translationY,
|
|
160
|
+
event.velocityY,
|
|
161
|
+
sheetHeight.value
|
|
162
|
+
)
|
|
163
|
+
) {
|
|
164
|
+
runOnJS(onClose)()
|
|
165
|
+
} else {
|
|
166
|
+
dragY.value = withSpring(0, { damping: 22, stiffness: 320 })
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
const windowHeight = window.height
|
|
171
|
+
const sheetStyle = useAnimatedStyle(() => {
|
|
172
|
+
if (reduceMotion) {
|
|
173
|
+
return {
|
|
174
|
+
opacity: progress.value,
|
|
175
|
+
transform: [{ translateY: dragY.value }],
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Until the first layout lands, the full window height keeps the
|
|
179
|
+
// sheet parked off-screen instead of flashing in place.
|
|
180
|
+
const height = sheetHeight.value || windowHeight
|
|
181
|
+
return {
|
|
182
|
+
opacity: 1,
|
|
183
|
+
transform: [
|
|
184
|
+
{ translateY: (1 - progress.value) * height + dragY.value },
|
|
185
|
+
],
|
|
186
|
+
}
|
|
187
|
+
}, [reduceMotion, windowHeight])
|
|
188
|
+
|
|
189
|
+
const backdropStyle = useAnimatedStyle(() => ({
|
|
190
|
+
opacity: progress.value,
|
|
191
|
+
}))
|
|
192
|
+
|
|
193
|
+
if (!mounted) return null
|
|
194
|
+
|
|
195
|
+
const maxHeight = resolveSheetMaxHeight(
|
|
196
|
+
windowHeight,
|
|
197
|
+
insets?.top ?? 0,
|
|
198
|
+
maxHeightFraction
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<Portal>
|
|
203
|
+
<Animated.View
|
|
204
|
+
style={[
|
|
205
|
+
StyleSheet.absoluteFill,
|
|
206
|
+
{ backgroundColor: backdropColor },
|
|
207
|
+
backdropStyle,
|
|
208
|
+
]}
|
|
209
|
+
testID={testID ? `${testID}-backdrop` : undefined}
|
|
210
|
+
// The sheet is the modal surface; VoiceOver skips the
|
|
211
|
+
// backdrop (it could not reach it past
|
|
212
|
+
// accessibilityViewIsModal anyway).
|
|
213
|
+
accessible={false}
|
|
214
|
+
importantForAccessibility="no-hide-descendants"
|
|
215
|
+
>
|
|
216
|
+
<Pressable
|
|
217
|
+
style={StyleSheet.absoluteFill}
|
|
218
|
+
onPress={dismissOnBackdropPress ? onClose : undefined}
|
|
219
|
+
/>
|
|
220
|
+
</Animated.View>
|
|
221
|
+
|
|
222
|
+
<GestureDetector gesture={pan}>
|
|
223
|
+
<Animated.View
|
|
224
|
+
onLayout={onSheetLayout}
|
|
225
|
+
accessibilityViewIsModal
|
|
226
|
+
accessibilityLabel={accessibilityLabel}
|
|
227
|
+
testID={testID}
|
|
228
|
+
style={[
|
|
229
|
+
styles.sheet,
|
|
230
|
+
{
|
|
231
|
+
maxHeight,
|
|
232
|
+
backgroundColor,
|
|
233
|
+
borderTopLeftRadius: topRadius,
|
|
234
|
+
borderTopRightRadius: topRadius,
|
|
235
|
+
paddingBottom: insets?.bottom ?? 0,
|
|
236
|
+
},
|
|
237
|
+
sheetStyle,
|
|
238
|
+
style,
|
|
239
|
+
]}
|
|
240
|
+
>
|
|
241
|
+
{showHandle ? (
|
|
242
|
+
<View
|
|
243
|
+
style={[
|
|
244
|
+
styles.handle,
|
|
245
|
+
{ backgroundColor: handleColor },
|
|
246
|
+
]}
|
|
247
|
+
/>
|
|
248
|
+
) : null}
|
|
249
|
+
{children}
|
|
250
|
+
</Animated.View>
|
|
251
|
+
</GestureDetector>
|
|
252
|
+
</Portal>
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
BottomSheet.displayName = 'BottomSheet'
|
|
257
|
+
|
|
258
|
+
const styles = StyleSheet.create({
|
|
259
|
+
sheet: {
|
|
260
|
+
position: 'absolute',
|
|
261
|
+
left: 0,
|
|
262
|
+
right: 0,
|
|
263
|
+
bottom: 0,
|
|
264
|
+
overflow: 'hidden',
|
|
265
|
+
},
|
|
266
|
+
handle: {
|
|
267
|
+
alignSelf: 'center',
|
|
268
|
+
width: 36,
|
|
269
|
+
height: 4,
|
|
270
|
+
borderRadius: 2,
|
|
271
|
+
marginTop: 8,
|
|
272
|
+
marginBottom: 4,
|
|
273
|
+
},
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
export default BottomSheet
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bottom-sheet gesture arithmetic.
|
|
3
|
+
*
|
|
4
|
+
* Pure and RN-free (the `theme/breakpoint.ts` pattern) so the dismiss
|
|
5
|
+
* decision — the part of a sheet that feels wrong when it is wrong — is
|
|
6
|
+
* unit-testable under vitest. `BottomSheet` wires these into the pan
|
|
7
|
+
* gesture; they also run as Reanimated worklets, so nothing here may close
|
|
8
|
+
* over module state.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Dragging past this fraction of the sheet's height dismisses on release. */
|
|
12
|
+
export const SHEET_DISMISS_FRACTION = 0.25
|
|
13
|
+
|
|
14
|
+
/** A downward fling at or above this velocity (pt/s) dismisses regardless. */
|
|
15
|
+
export const SHEET_DISMISS_VELOCITY = 800
|
|
16
|
+
|
|
17
|
+
/** Default cap: a sheet covers at most this fraction of the window. */
|
|
18
|
+
export const SHEET_MAX_HEIGHT_FRACTION = 0.9
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The sheet follows the finger downward only — upward drag is pinned so the
|
|
22
|
+
* sheet feels anchored rather than lifting off its resting position.
|
|
23
|
+
*/
|
|
24
|
+
export function clampSheetDrag(translationY: number): number {
|
|
25
|
+
'worklet'
|
|
26
|
+
return Math.max(0, translationY)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Whether a released drag should dismiss the sheet: past the distance
|
|
31
|
+
* threshold, or a genuine downward fling. An upward fling never dismisses,
|
|
32
|
+
* whatever distance was covered first.
|
|
33
|
+
*/
|
|
34
|
+
export function shouldDismissSheet(
|
|
35
|
+
translationY: number,
|
|
36
|
+
velocityY: number,
|
|
37
|
+
sheetHeight: number
|
|
38
|
+
): boolean {
|
|
39
|
+
'worklet'
|
|
40
|
+
if (velocityY <= -SHEET_DISMISS_VELOCITY) return false
|
|
41
|
+
if (velocityY >= SHEET_DISMISS_VELOCITY) return translationY > 0
|
|
42
|
+
return (
|
|
43
|
+
sheetHeight > 0 && translationY >= sheetHeight * SHEET_DISMISS_FRACTION
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The tallest a sheet may grow: the capped fraction of the window, minus
|
|
49
|
+
* whatever top inset (status bar / notch) must stay visible above it.
|
|
50
|
+
*/
|
|
51
|
+
export function resolveSheetMaxHeight(
|
|
52
|
+
windowHeight: number,
|
|
53
|
+
topInset: number = 0,
|
|
54
|
+
maxHeightFraction: number = SHEET_MAX_HEIGHT_FRACTION
|
|
55
|
+
): number {
|
|
56
|
+
const capped = windowHeight * maxHeightFraction
|
|
57
|
+
return Math.max(0, Math.min(capped, windowHeight - topInset))
|
|
58
|
+
}
|