廓形仪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.
 
 

345 lines
9.6 KiB

'use client';
import React from 'react';
import { View, Pressable, ScrollView, ViewStyle } from 'react-native';
import {
Motion,
createMotionAnimatedComponent,
AnimatePresence,
MotionComponentProps,
} from '@legendapp/motion';
import { createPopover } from '@gluestack-ui/popover';
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 = 'POPOVER';
type IMotionViewProps = React.ComponentProps<typeof View> &
MotionComponentProps<typeof View, ViewStyle, unknown, unknown, unknown>;
const MotionView = Motion.View as React.ComponentType<IMotionViewProps>;
const UIPopover = createPopover({
Root: withStyleContext(View, SCOPE),
Arrow: MotionView,
Backdrop: AnimatedPressable,
Body: ScrollView,
CloseButton: Pressable,
Content: MotionView,
Footer: View,
Header: View,
AnimatePresence: AnimatePresence,
});
cssInterop(MotionView, { className: 'style' });
cssInterop(AnimatedPressable, { className: 'style' });
const popoverStyle = tva({
base: 'group/popover w-full h-full justify-center items-center web:pointer-events-none',
variants: {
size: {
xs: '',
sm: '',
md: '',
lg: '',
full: '',
},
},
});
const popoverArrowStyle = tva({
base: 'bg-background-0 z-[1] border absolute overflow-hidden h-3.5 w-3.5 border-outline-100',
variants: {
placement: {
'top left':
'data-[flip=false]:border-t-0 data-[flip=false]:border-l-0 data-[flip=true]:border-b-0 data-[flip=true]:border-r-0',
'top':
'data-[flip=false]:border-t-0 data-[flip=false]:border-l-0 data-[flip=true]:border-b-0 data-[flip=true]:border-r-0',
'top right':
'data-[flip=false]:border-t-0 data-[flip=false]:border-l-0 data-[flip=true]:border-b-0 data-[flip=true]:border-r-0',
'bottom':
'data-[flip=false]:border-b-0 data-[flip=false]:border-r-0 data-[flip=true]:border-t-0 data-[flip=true]:border-l-0',
'bottom left':
'data-[flip=false]:border-b-0 data-[flip=false]:border-r-0 data-[flip=true]:border-t-0 data-[flip=true]:border-l-0',
'bottom right':
'data-[flip=false]:border-b-0 data-[flip=false]:border-r-0 data-[flip=true]:border-t-0 data-[flip=true]:border-l-0',
'left':
'data-[flip=false]:border-l-0 data-[flip=false]:border-b-0 data-[flip=true]:border-r-0 data-[flip=true]:border-t-0',
'left top':
'data-[flip=false]:border-l-0 data-[flip=false]:border-b-0 data-[flip=true]:border-r-0 data-[flip=true]:border-t-0',
'left bottom':
'data-[flip=false]:border-l-0 data-[flip=false]:border-b-0 data-[flip=true]:border-r-0 data-[flip=true]:border-t-0',
'right':
'data-[flip=false]:border-r-0 data-[flip=false]:border-t-0 data-[flip=true]:border-l-0 data-[flip=true]:border-b-0',
'right top':
'data-[flip=false]:border-r-0 data-[flip=false]:border-t-0 data-[flip=true]:border-l-0 data-[flip=true]:border-b-0',
'right bottom':
'data-[flip=false]:border-r-0 data-[flip=false]:border-t-0 data-[flip=true]:border-l-0 data-[flip=true]:border-b-0',
},
},
});
const popoverBackdropStyle = tva({
base: 'absolute left-0 top-0 right-0 bottom-0 web:cursor-default',
});
const popoverCloseButtonStyle = tva({
base: 'group/popover-close-button z-[1] rounded-sm data-[focus-visible=true]:web:bg-background-100 web:outline-0 web:cursor-pointer',
});
const popoverContentStyle = tva({
base: 'bg-background-0 rounded-lg overflow-hidden border border-outline-100 w-full',
parentVariants: {
size: {
xs: 'max-w-[360px] p-3.5',
sm: 'max-w-[420px] p-4',
md: 'max-w-[510px] p-[18px]',
lg: 'max-w-[640px] p-5',
full: 'p-6',
},
},
});
const popoverHeaderStyle = tva({
base: 'flex-row justify-between items-center',
});
const popoverBodyStyle = tva({
base: '',
});
const popoverFooterStyle = tva({
base: 'flex-row justify-between items-center',
});
type IPopoverProps = React.ComponentProps<typeof UIPopover> &
VariantProps<typeof popoverStyle> & { className?: string };
type IPopoverArrowProps = React.ComponentProps<typeof UIPopover.Arrow> &
VariantProps<typeof popoverArrowStyle> & { className?: string };
type IPopoverContentProps = React.ComponentProps<typeof UIPopover.Content> &
VariantProps<typeof popoverContentStyle> & { className?: string };
type IPopoverHeaderProps = React.ComponentProps<typeof UIPopover.Header> &
VariantProps<typeof popoverHeaderStyle> & { className?: string };
type IPopoverFooterProps = React.ComponentProps<typeof UIPopover.Footer> &
VariantProps<typeof popoverFooterStyle> & { className?: string };
type IPopoverBodyProps = React.ComponentProps<typeof UIPopover.Body> &
VariantProps<typeof popoverBodyStyle> & { className?: string };
type IPopoverBackdropProps = React.ComponentProps<typeof UIPopover.Backdrop> &
VariantProps<typeof popoverBackdropStyle> & { className?: string };
type IPopoverCloseButtonProps = React.ComponentProps<
typeof UIPopover.CloseButton
> &
VariantProps<typeof popoverCloseButtonStyle> & { className?: string };
const Popover = React.forwardRef<
React.ComponentRef<typeof UIPopover>,
IPopoverProps
>(function Popover(
{ className, size = 'md', placement = 'bottom', ...props },
ref
) {
return (
<UIPopover
ref={ref}
placement={placement}
{...props}
className={popoverStyle({ size, class: className })}
context={{ size, placement }}
pointerEvents="box-none"
/>
);
});
const PopoverContent = React.forwardRef<
React.ComponentRef<typeof UIPopover.Content>,
IPopoverContentProps
>(function PopoverContent({ className, size, ...props }, ref) {
const { size: parentSize } = useStyleContext(SCOPE);
return (
<UIPopover.Content
ref={ref}
transition={{
type: 'spring',
damping: 18,
stiffness: 250,
mass: 0.9,
opacity: {
type: 'timing',
duration: 50,
delay: 50,
},
}}
{...props}
className={popoverContentStyle({
parentVariants: {
size: parentSize,
},
size,
class: className,
})}
pointerEvents="auto"
/>
);
});
const PopoverArrow = React.forwardRef<
React.ComponentRef<typeof UIPopover.Arrow>,
IPopoverArrowProps
>(function PopoverArrow({ className, ...props }, ref) {
const { placement } = useStyleContext(SCOPE);
return (
<UIPopover.Arrow
ref={ref}
transition={{
type: 'spring',
damping: 18,
stiffness: 250,
mass: 0.9,
opacity: {
type: 'timing',
duration: 50,
delay: 50,
},
}}
{...props}
className={popoverArrowStyle({
class: className,
placement,
})}
/>
);
});
const PopoverBackdrop = React.forwardRef<
React.ComponentRef<typeof UIPopover.Backdrop>,
IPopoverBackdropProps
>(function PopoverBackdrop({ className, ...props }, ref) {
return (
<UIPopover.Backdrop
ref={ref}
{...props}
initial={{
opacity: 0,
}}
animate={{
opacity: 0.1,
}}
exit={{
opacity: 0,
}}
transition={{
type: 'spring',
damping: 18,
stiffness: 450,
mass: 0.9,
opacity: {
type: 'timing',
duration: 50,
delay: 50,
},
}}
className={popoverBackdropStyle({
class: className,
})}
/>
);
});
const PopoverBody = React.forwardRef<
React.ComponentRef<typeof UIPopover.Body>,
IPopoverBodyProps
>(function PopoverBody({ className, ...props }, ref) {
return (
<UIPopover.Body
ref={ref}
{...props}
className={popoverBodyStyle({
class: className,
})}
/>
);
});
const PopoverCloseButton = React.forwardRef<
React.ComponentRef<typeof UIPopover.CloseButton>,
IPopoverCloseButtonProps
>(function PopoverCloseButton({ className, ...props }, ref) {
return (
<UIPopover.CloseButton
ref={ref}
{...props}
className={popoverCloseButtonStyle({
class: className,
})}
/>
);
});
const PopoverFooter = React.forwardRef<
React.ComponentRef<typeof UIPopover.Footer>,
IPopoverFooterProps
>(function PopoverFooter({ className, ...props }, ref) {
return (
<UIPopover.Footer
ref={ref}
{...props}
className={popoverFooterStyle({
class: className,
})}
/>
);
});
const PopoverHeader = React.forwardRef<
React.ComponentRef<typeof UIPopover.Header>,
IPopoverHeaderProps
>(function PopoverHeader({ className, ...props }, ref) {
return (
<UIPopover.Header
ref={ref}
{...props}
className={popoverHeaderStyle({
class: className,
})}
/>
);
});
Popover.displayName = 'Popover';
PopoverArrow.displayName = 'PopoverArrow';
PopoverBackdrop.displayName = 'PopoverBackdrop';
PopoverContent.displayName = 'PopoverContent';
PopoverHeader.displayName = 'PopoverHeader';
PopoverFooter.displayName = 'PopoverFooter';
PopoverBody.displayName = 'PopoverBody';
PopoverCloseButton.displayName = 'PopoverCloseButton';
export {
Popover,
PopoverBackdrop,
PopoverArrow,
PopoverCloseButton,
PopoverFooter,
PopoverHeader,
PopoverBody,
PopoverContent,
};