/** * 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 { cloneElement, createContext, isValidElement, useCallback, useContext, useId, useRef, } from 'react'; import type { CreateModal, ModalBodyComponent, ModalComponent, ModalContentComponent, ModalContext, ModalOverlayComponent, ModalPortalComponent, ModalTitleComponent, ModalTriggerComponent, } from './types'; import { composeEventHandlers, useUncontrolled } from '@crossed/core'; import { Pressable, Text, View } from 'react-native'; import { Portal } from '@gorhom/portal'; import { Focus, useEscape } from './Focus'; export * from './types'; export const createModal: CreateModal = () => { const modalContext = createContext({} as ModalContext); const Modal: ModalComponent = ({ children, open: openProps, defaultOpen = false, onOpenChange, }) => { const titleIdRef = useRef(); const descriptionIdRef = useRef(); const [open, setOpen] = useUncontrolled({ value: openProps, defaultValue: defaultOpen, onChange: onOpenChange, }); return ( {children} ); }; const ModalContent: ModalContentComponent = (props) => { const { titleIdRef, descriptionIdRef, setOpen } = useContext(modalContext); const escapeProps = useEscape(() => setOpen(false)); return ( ); }; const ModalOverlay: ModalOverlayComponent = ({ closeOnPress, ...props }) => { const { setOpen } = useContext(modalContext); const onPress = useCallback(() => { setOpen(false); }, [setOpen]); return ( ); }; const ModalTitle: ModalTitleComponent = ({ nativeID, id: idProps, ...props }) => { const { titleIdRef } = useContext(modalContext); const localId = useId(); const id = idProps || nativeID || `modal-title${localId}`; titleIdRef.current = id; return ; }; const ModalBody: ModalBodyComponent = ({ nativeID, id: idProps, ...props }) => { const { descriptionIdRef } = useContext(modalContext); const localId = useId(); const id = idProps || nativeID || `modal-body${localId}`; descriptionIdRef.current = id; return ; }; const ModalPortal: ModalPortalComponent = ({ children, ...props }) => { const context = useContext(modalContext); return ( {children} ); }; const ModalTrigger: ModalTriggerComponent = ({ children, asChild = false, ...props }) => { const { open, setOpen } = useContext(modalContext); const onPressOut = useCallback(() => { setOpen(!open); }, [open, setOpen]); return asChild && isValidElement(children) ? ( cloneElement(children, { role: 'button', ...props, onPressOut: composeEventHandlers(props.onPressOut, onPressOut), } as any) ) : ( {})} > {children} ); }; return { modalContext, Modal, ModalContent, ModalOverlay, ModalTitle, ModalTrigger, ModalPortal, ModalBody, }; }; const { Modal, ModalContent, ModalOverlay, ModalTitle, ModalTrigger, ModalPortal, ModalBody, } = createModal(); export { Modal, ModalContent, ModalOverlay, ModalTitle, ModalTrigger, ModalPortal, ModalBody, };