* 4.7-alpha3 (#62) * doc * Optimize possible null Pointers and parts of Ux * fix: mulity index training error * feat: doc and rename question guide * fix ios speech input (#59) * fix: prompt editor variables nowrap (#61) * change openapi import in http module with curl import (#60) * chore(ui): dataset import modal ui (#58) * chore(ui): dataset import modal ui * use component * fix height * 4.7 (#63) * fix: claude3 image type verification failed (#1038) (#1040) * perf: curl import modal * doc img * perf: adapt cohere rerank * perf: code * perf: input style * doc --------- Co-authored-by: xiaotian <dimsky@163.com> * fix: ts * docker deploy * perf: prompt call * doc * ts * finish ui * perf: outlink detail ux * perf: user schema * fix: plugin update * feat: get current time plugin * fix: ts * perf: fetch anamation * perf: mark ux * doc * perf: select app ux * fix: split text custom string conflict * peref: inform readed * doc * memo flow component * perf: version * faq * feat: flow max runtimes * feat: similarity tip * feat: auto detect file encoding * Supports asymmetric vector model * fix: ts * perf: max w * move code * perf: hide whisper * fix: ts * feat: system msg modal * perf: catch error * perf: inform tip * fix: inform --------- Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com> Co-authored-by: xiaotian <dimsky@163.com>
136 lines
3.1 KiB
TypeScript
136 lines
3.1 KiB
TypeScript
import React, { useRef, useState } from 'react';
|
|
import {
|
|
Menu,
|
|
MenuList,
|
|
MenuItem,
|
|
Box,
|
|
useOutsideClick,
|
|
MenuButton,
|
|
MenuItemProps
|
|
} from '@chakra-ui/react';
|
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
|
|
|
type MenuItemType = 'primary' | 'danger';
|
|
|
|
interface Props {
|
|
width?: number | string;
|
|
offset?: [number, number];
|
|
Button: React.ReactNode;
|
|
trigger?: 'hover' | 'click';
|
|
menuList: {
|
|
isActive?: boolean;
|
|
label: string | React.ReactNode;
|
|
icon?: string;
|
|
type?: MenuItemType;
|
|
onClick: () => any;
|
|
}[];
|
|
}
|
|
|
|
const MyMenu = ({
|
|
width = 'auto',
|
|
trigger = 'hover',
|
|
offset = [0, 5],
|
|
Button,
|
|
menuList
|
|
}: Props) => {
|
|
const typeMapStyle: Record<MenuItemType, MenuItemProps> = {
|
|
primary: {
|
|
_hover: {
|
|
backgroundColor: 'primary.50',
|
|
color: 'primary.600'
|
|
}
|
|
},
|
|
danger: {
|
|
_hover: {
|
|
color: 'red.600',
|
|
background: 'red.1'
|
|
}
|
|
}
|
|
};
|
|
const menuItemStyles: MenuItemProps = {
|
|
borderRadius: 'sm',
|
|
py: 3,
|
|
display: 'flex',
|
|
alignItems: 'center'
|
|
};
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
const closeTimer = useRef<any>();
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
useOutsideClick({
|
|
ref: ref,
|
|
handler: () => {
|
|
setIsOpen(false);
|
|
}
|
|
});
|
|
|
|
return (
|
|
<Menu offset={offset} isOpen={isOpen} autoSelect={false} direction={'ltr'} isLazy>
|
|
<Box
|
|
ref={ref}
|
|
onMouseEnter={() => {
|
|
if (trigger === 'hover') {
|
|
setIsOpen(true);
|
|
}
|
|
clearTimeout(closeTimer.current);
|
|
}}
|
|
onMouseLeave={() => {
|
|
if (trigger === 'hover') {
|
|
closeTimer.current = setTimeout(() => {
|
|
setIsOpen(false);
|
|
}, 100);
|
|
}
|
|
}}
|
|
>
|
|
<Box
|
|
position={'relative'}
|
|
onClickCapture={() => {
|
|
if (trigger === 'click') {
|
|
setIsOpen(!isOpen);
|
|
}
|
|
}}
|
|
>
|
|
<MenuButton
|
|
w={'100%'}
|
|
h={'100%'}
|
|
position={'absolute'}
|
|
top={0}
|
|
right={0}
|
|
bottom={0}
|
|
left={0}
|
|
/>
|
|
<Box position={'relative'}>{Button}</Box>
|
|
</Box>
|
|
<MenuList
|
|
minW={isOpen ? `${width}px !important` : 0}
|
|
p={'6px'}
|
|
border={'1px solid #fff'}
|
|
boxShadow={
|
|
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
|
|
}
|
|
>
|
|
{menuList.map((item, i) => (
|
|
<MenuItem
|
|
key={i}
|
|
{...menuItemStyles}
|
|
{...typeMapStyle[item.type || 'primary']}
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
setIsOpen(false);
|
|
item.onClick && item.onClick();
|
|
}}
|
|
color={item.isActive ? 'primary.700' : 'myGray.600'}
|
|
whiteSpace={'pre-wrap'}
|
|
>
|
|
{!!item.icon && <MyIcon name={item.icon as any} w={'16px'} mr={2} />}
|
|
{item.label}
|
|
</MenuItem>
|
|
))}
|
|
</MenuList>
|
|
</Box>
|
|
</Menu>
|
|
);
|
|
};
|
|
|
|
export default MyMenu;
|