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

217 lines
5.3 KiB

'use client';
import React from 'react';
import { createMenu } from '@gluestack-ui/menu';
import { tva } from '@gluestack-ui/nativewind-utils/tva';
import { cssInterop } from 'nativewind';
import { Pressable, Text, View, ViewStyle } from 'react-native';
import {
Motion,
AnimatePresence,
MotionComponentProps,
} from '@legendapp/motion';
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
type IMotionViewProps = React.ComponentProps<typeof View> &
MotionComponentProps<typeof View, ViewStyle, unknown, unknown, unknown>;
const MotionView = Motion.View as React.ComponentType<IMotionViewProps>;
const menuStyle = tva({
base: 'rounded-md bg-background-0 border border-outline-100 p-1 shadow-hard-5',
});
const menuItemStyle = tva({
base: 'min-w-[200px] p-3 flex-row items-center rounded data-[hover=true]:bg-background-50 data-[active=true]:bg-background-100 data-[focus=true]:bg-background-50 data-[focus=true]:web:outline-none data-[focus=true]:web:outline-0 data-[disabled=true]:opacity-40 data-[disabled=true]:web:cursor-not-allowed data-[focus-visible=true]:web:outline-2 data-[focus-visible=true]:web:outline-primary-700 data-[focus-visible=true]:web:outline data-[focus-visible=true]:web:cursor-pointer data-[disabled=true]:data-[focus=true]:bg-transparent',
});
const menuBackdropStyle = tva({
base: 'absolute top-0 bottom-0 left-0 right-0 web:cursor-default',
// add this classnames if you want to give background color to backdrop
// opacity-50 bg-background-500,
});
const menuSeparatorStyle = tva({
base: 'bg-background-200 h-px w-full',
});
const menuItemLabelStyle = tva({
base: 'text-typography-700 font-normal font-body',
variants: {
isTruncated: {
true: 'web:truncate',
},
bold: {
true: 'font-bold',
},
underline: {
true: 'underline',
},
strikeThrough: {
true: 'line-through',
},
size: {
'2xs': 'text-2xs',
'xs': 'text-xs',
'sm': 'text-sm',
'md': 'text-base',
'lg': 'text-lg',
'xl': 'text-xl',
'2xl': 'text-2xl',
'3xl': 'text-3xl',
'4xl': 'text-4xl',
'5xl': 'text-5xl',
'6xl': 'text-6xl',
},
sub: {
true: 'text-xs',
},
italic: {
true: 'italic',
},
highlight: {
true: 'bg-yellow-500',
},
},
});
const BackdropPressable = React.forwardRef<
React.ComponentRef<typeof Pressable>,
React.ComponentPropsWithoutRef<typeof Pressable> &
VariantProps<typeof menuBackdropStyle>
>(function BackdropPressable({ className, ...props }, ref) {
return (
<Pressable
ref={ref}
className={menuBackdropStyle({
class: className,
})}
{...props}
/>
);
});
type IMenuItemProps = VariantProps<typeof menuItemStyle> & {
className?: string;
} & React.ComponentPropsWithoutRef<typeof Pressable>;
const Item = React.forwardRef<
React.ComponentRef<typeof Pressable>,
IMenuItemProps
>(function Item({ className, ...props }, ref) {
return (
<Pressable
ref={ref}
className={menuItemStyle({
class: className,
})}
{...props}
/>
);
});
const Separator = React.forwardRef<
React.ComponentRef<typeof View>,
React.ComponentPropsWithoutRef<typeof View> &
VariantProps<typeof menuSeparatorStyle>
>(function Separator({ className, ...props }, ref) {
return (
<View
ref={ref}
className={menuSeparatorStyle({ class: className })}
{...props}
/>
);
});
export const UIMenu = createMenu({
Root: MotionView,
Item: Item,
Label: Text,
Backdrop: BackdropPressable,
AnimatePresence: AnimatePresence,
Separator: Separator,
});
cssInterop(MotionView, { className: 'style' });
type IMenuProps = React.ComponentProps<typeof UIMenu> &
VariantProps<typeof menuStyle> & { className?: string };
type IMenuItemLabelProps = React.ComponentProps<typeof UIMenu.ItemLabel> &
VariantProps<typeof menuItemLabelStyle> & { className?: string };
const Menu = React.forwardRef<React.ComponentRef<typeof UIMenu>, IMenuProps>(
function Menu({ className, ...props }, ref) {
return (
<UIMenu
ref={ref}
initial={{
opacity: 0,
scale: 0.8,
}}
animate={{
opacity: 1,
scale: 1,
}}
exit={{
opacity: 0,
scale: 0.8,
}}
transition={{
type: 'timing',
duration: 100,
}}
className={menuStyle({
class: className,
})}
{...props}
/>
);
}
);
const MenuItem = UIMenu.Item;
const MenuItemLabel = React.forwardRef<
React.ComponentRef<typeof UIMenu.ItemLabel>,
IMenuItemLabelProps
>(function MenuItemLabel(
{
className,
isTruncated,
bold,
underline,
strikeThrough,
size = 'md',
sub,
italic,
highlight,
...props
},
ref
) {
return (
<UIMenu.ItemLabel
ref={ref}
className={menuItemLabelStyle({
isTruncated,
bold,
underline,
strikeThrough,
size,
sub,
italic,
highlight,
class: className,
})}
{...props}
/>
);
});
const MenuSeparator = UIMenu.Separator;
Menu.displayName = 'Menu';
MenuItem.displayName = 'MenuItem';
MenuItemLabel.displayName = 'MenuItemLabel';
MenuSeparator.displayName = 'MenuSeparator';
export { Menu, MenuItem, MenuItemLabel, MenuSeparator };