/** * Copyright (c) Paymium. * * This source code is licensed under the MIT license found in the * LICENSE file in the root of this projects source tree. */ import { ComponentProps, forwardRef, memo, PropsWithChildren, RefAttributes, useEffect, useRef, } from 'react'; import { Sheet } from './Sheet/index'; import { composeRefs, createScope, withStaticProperties } from '@crossed/core'; import { composeStyles, createStyles, CrossedMethods, inlineStyle, isWeb, } from '@crossed/styled'; import { ActionSheetRef } from '@crossed/sheet'; import { View } from 'react-native'; import { Floating, useFloatingContext } from './Floating'; import { autoUpdate, offset, Placement, useFloating } from '@floating-ui/react'; import { flip } from '@floating-ui/dom'; import { FadeIn, FadeOut } from 'react-native-reanimated'; import { useMedia } from '../useMedia'; import { FocusOn } from 'react-focus-on'; export type PopoverConfigContext = { showSheet?: boolean; triggerStrategy: 'onPointerEnter' | 'onPress'; }; export const [PopoverConfigProvider, usePopoverConfig] = createScope({} as PopoverConfigContext); const useFloatinCompat = isWeb ? (placement: Placement, offSetValue: number) => useFloating({ placement: placement, middleware: [flip({ crossAxis: true }), offset(offSetValue)], whileElementsMounted: autoUpdate, }) : () => ({ refs: {}, floatingStyles: {}, }); const stylesDyn = createStyles(() => ({ dyn: (e: any) => e })); type FloatingUiContext = Pick< ReturnType, 'refs' | 'floatingStyles' >; const [FloatingUiProvider, useFloatingUi] = createScope( {} as FloatingUiContext ); type RootProps = ComponentProps & { placement?: Placement; offsetValue?: number; }; export const Root = memo( ({ children, placement = 'bottom-end', triggerStrategy = 'onPress', offsetValue = 10, ...props }: RootProps) => { const { refs, floatingStyles } = useFloatinCompat(placement, offsetValue); const { md } = useMedia(); return ( {children} ); } ); type TriggerProps = ComponentProps; export const Trigger = memo>( forwardRef((props, ref) => { const { refs } = useFloatingUi(); return ( ); }) ); type ContentProps = PropsWithChildren<{ style?: CrossedMethods }>; export const Content = memo>( forwardRef(({ children, style }, ref) => { const { showSheet } = usePopoverConfig(); return showSheet ? ( ) : ( ); }) ); type ContentWebProps = PropsWithChildren<{ style?: CrossedMethods }>; const ContentWeb = memo>( forwardRef(({ children, style }, ref) => { const { refs, floatingStyles } = useFloatingUi(); const { onClose, open } = useFloatingContext(); const { triggerStrategy } = usePopoverConfig(); return ( ({ base: { position: 'absolute' }, })), stylesDyn.dyn(floatingStyles), style )} > {children} ); }) ); const ContentNative = ({ children, }: PropsWithChildren<{ style?: CrossedMethods }>) => { const { open, onClose } = useFloatingContext(); const refSheet = useRef(null); useEffect(() => { if (open) { refSheet.current?.show(); } else { refSheet.current?.hide(); } }, [open]); return ( {children} ); }; export const Popover = withStaticProperties(Root, { Trigger, Content, });