廓形仪rn版本-技术调研
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

276 lines
6.8 KiB

'use client';
import React from 'react';
import { createModal } from '@gluestack-ui/modal';
import { Pressable, View, ScrollView, ViewStyle } from 'react-native';
import {
Motion,
AnimatePresence,
createMotionAnimatedComponent,
MotionComponentProps,
} from '@legendapp/motion';
import { tva } from '@gluestack-ui/nativewind-utils/tva';
import {
withStyleContext,
useStyleContext,
} from '@gluestack-ui/nativewind-utils/withStyleContext';
import { cssInterop } from 'nativewind';
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
type IAnimatedPressableProps = React.ComponentProps<typeof Pressable> &
MotionComponentProps<typeof Pressable, ViewStyle, unknown, unknown, unknown>;
const AnimatedPressable = createMotionAnimatedComponent(
Pressable
) as React.ComponentType<IAnimatedPressableProps>;
const SCOPE = 'MODAL';
type IMotionViewProps = React.ComponentProps<typeof View> &
MotionComponentProps<typeof View, ViewStyle, unknown, unknown, unknown>;
const MotionView = Motion.View as React.ComponentType<IMotionViewProps>;
const UIModal = createModal({
Root: withStyleContext(View, SCOPE),
Backdrop: AnimatedPressable,
Content: MotionView,
Body: ScrollView,
CloseButton: Pressable,
Footer: View,
Header: View,
AnimatePresence: AnimatePresence,
});
cssInterop(AnimatedPressable, { className: 'style' });
cssInterop(MotionView, { className: 'style' });
const modalStyle = tva({
base: 'group/modal w-full h-full justify-center items-center web:pointer-events-none',
variants: {
size: {
xs: '',
sm: '',
md: '',
lg: '',
full: '',
},
},
});
const modalBackdropStyle = tva({
base: 'absolute left-0 top-0 right-0 bottom-0 bg-background-dark web:cursor-default',
});
const modalContentStyle = tva({
base: 'bg-background-0 rounded-md overflow-hidden border border-outline-100 shadow-hard-2 p-6',
parentVariants: {
size: {
xs: 'w-[60%] max-w-[360px]',
sm: 'w-[70%] max-w-[420px]',
md: 'w-[80%] max-w-[510px]',
lg: 'w-[90%] max-w-[640px]',
full: 'w-full',
},
},
});
const modalBodyStyle = tva({
base: 'mt-2 mb-6',
});
const modalCloseButtonStyle = tva({
base: 'group/modal-close-button z-10 rounded data-[focus-visible=true]:web:bg-background-100 web:outline-0 cursor-pointer',
});
const modalHeaderStyle = tva({
base: 'justify-between items-center flex-row',
});
const modalFooterStyle = tva({
base: 'flex-row justify-end items-center gap-2',
});
type IModalProps = React.ComponentProps<typeof UIModal> &
VariantProps<typeof modalStyle> & { className?: string };
type IModalBackdropProps = React.ComponentProps<typeof UIModal.Backdrop> &
VariantProps<typeof modalBackdropStyle> & { className?: string };
type IModalContentProps = React.ComponentProps<typeof UIModal.Content> &
VariantProps<typeof modalContentStyle> & { className?: string };
type IModalHeaderProps = React.ComponentProps<typeof UIModal.Header> &
VariantProps<typeof modalHeaderStyle> & { className?: string };
type IModalBodyProps = React.ComponentProps<typeof UIModal.Body> &
VariantProps<typeof modalBodyStyle> & { className?: string };
type IModalFooterProps = React.ComponentProps<typeof UIModal.Footer> &
VariantProps<typeof modalFooterStyle> & { className?: string };
type IModalCloseButtonProps = React.ComponentProps<typeof UIModal.CloseButton> &
VariantProps<typeof modalCloseButtonStyle> & { className?: string };
const Modal = React.forwardRef<React.ComponentRef<typeof UIModal>, IModalProps>(
({ className, size = 'md', ...props }, ref) => (
<UIModal
ref={ref}
{...props}
pointerEvents="box-none"
className={modalStyle({ size, class: className })}
context={{ size }}
/>
)
);
const ModalBackdrop = React.forwardRef<
React.ComponentRef<typeof UIModal.Backdrop>,
IModalBackdropProps
>(function ModalBackdrop({ className, ...props }, ref) {
return (
<UIModal.Backdrop
ref={ref}
initial={{
opacity: 0,
}}
animate={{
opacity: 0.5,
}}
exit={{
opacity: 0,
}}
transition={{
type: 'spring',
damping: 18,
stiffness: 250,
opacity: {
type: 'timing',
duration: 250,
},
}}
{...props}
className={modalBackdropStyle({
class: className,
})}
/>
);
});
const ModalContent = React.forwardRef<
React.ComponentRef<typeof UIModal.Content>,
IModalContentProps
>(function ModalContent({ className, size, ...props }, ref) {
const { size: parentSize } = useStyleContext(SCOPE);
return (
<UIModal.Content
ref={ref}
initial={{
opacity: 0,
scale: 0.9,
}}
animate={{
opacity: 1,
scale: 1,
}}
exit={{
opacity: 0,
}}
transition={{
type: 'spring',
damping: 18,
stiffness: 250,
opacity: {
type: 'timing',
duration: 250,
},
}}
{...props}
className={modalContentStyle({
parentVariants: {
size: parentSize,
},
size,
class: className,
})}
pointerEvents="auto"
/>
);
});
const ModalHeader = React.forwardRef<
React.ComponentRef<typeof UIModal.Header>,
IModalHeaderProps
>(function ModalHeader({ className, ...props }, ref) {
return (
<UIModal.Header
ref={ref}
{...props}
className={modalHeaderStyle({
class: className,
})}
/>
);
});
const ModalBody = React.forwardRef<
React.ComponentRef<typeof UIModal.Body>,
IModalBodyProps
>(function ModalBody({ className, ...props }, ref) {
return (
<UIModal.Body
ref={ref}
{...props}
className={modalBodyStyle({
class: className,
})}
/>
);
});
const ModalFooter = React.forwardRef<
React.ComponentRef<typeof UIModal.Footer>,
IModalFooterProps
>(function ModalFooter({ className, ...props }, ref) {
return (
<UIModal.Footer
ref={ref}
{...props}
className={modalFooterStyle({
class: className,
})}
/>
);
});
const ModalCloseButton = React.forwardRef<
React.ComponentRef<typeof UIModal.CloseButton>,
IModalCloseButtonProps
>(function ModalCloseButton({ className, ...props }, ref) {
return (
<UIModal.CloseButton
ref={ref}
{...props}
className={modalCloseButtonStyle({
class: className,
})}
/>
);
});
Modal.displayName = 'Modal';
ModalBackdrop.displayName = 'ModalBackdrop';
ModalContent.displayName = 'ModalContent';
ModalHeader.displayName = 'ModalHeader';
ModalBody.displayName = 'ModalBody';
ModalFooter.displayName = 'ModalFooter';
ModalCloseButton.displayName = 'ModalCloseButton';
export {
Modal,
ModalBackdrop,
ModalContent,
ModalCloseButton,
ModalHeader,
ModalBody,
ModalFooter,
};