lobe-chat
150 строк · 3.2 Кб
1import { ActionIcon } from '@lobehub/ui';
2import { ConfigProvider, Popover, TooltipProps } from 'antd';
3import { createStyles, useTheme } from 'antd-style';
4import { XIcon } from 'lucide-react';
5import { CSSProperties, type FC, type ReactNode } from 'react';
6import { Flexbox } from 'react-layout-kit';
7
8const useStyle = createStyles(({ css }) => {
9return {
10close: css`
11color: white;
12`,
13container: css`
14position: relative;
15`,
16footer: css`
17display: flex;
18justify-content: end;
19width: 100%;
20`,
21overlay: css`
22.ant-popover-inner {
23border: none;
24}
25`,
26tip: css`
27position: absolute;
28inset-inline-start: 50%;
29transform: translate(-50%);
30`,
31};
32});
33
34export interface TipGuideProps {
35/**
36* 引导内容
37*/
38children?: ReactNode;
39/**
40* 类名
41*/
42className?: string;
43/**
44* 默认时候的打开状态
45*/
46defaultOpen?: boolean;
47/**
48* 用于自定义 footer 部分的 render api
49*/
50footerRender?: (dom: ReactNode) => ReactNode;
51/**
52* 最大宽度
53*/
54maxWidth?: number;
55/**
56* 纵向偏移值
57*/
58offsetY?: number;
59/**
60* 当 open 属性变化时候的触发
61*/
62onOpenChange: (open: boolean) => void;
63/**
64* 受控的 open 属性
65*/
66open?: boolean;
67/**
68* Tooltip 位置,默认为 bottom
69*/
70placement?: TooltipProps['placement'];
71/**
72* style
73*/
74style?: CSSProperties;
75tip?: boolean;
76/**
77* 引导标题
78*/
79title: string;
80}
81
82const TipGuide: FC<TipGuideProps> = ({
83children,
84placement = 'bottom',
85title,
86offsetY,
87maxWidth = 300,
88className,
89style,
90open,
91onOpenChange: setOpen,
92}) => {
93const token = useTheme();
94const { styles, cx } = useStyle();
95
96return (
97<ConfigProvider
98theme={{
99components: {
100Badge: { fontSize: 12, lineHeight: 1 },
101Button: { colorPrimary: token.blue7 },
102Checkbox: {
103colorPrimary: token.blue7,
104colorText: token.colorTextLightSolid,
105},
106Popover: { colorText: token.colorTextLightSolid },
107},
108}}
109>
110{open ? (
111<div className={styles.container}>
112<div
113style={{
114marginTop: offsetY,
115}}
116>
117<Popover
118arrow={{ pointAtCenter: true }}
119color={'blue'}
120content={
121<Flexbox gap={24} horizontal style={{ userSelect: 'none' }}>
122<div>{title}</div>
123<ActionIcon
124className={styles.close}
125icon={XIcon}
126onClick={() => {
127setOpen(false);
128}}
129size={'small'}
130/>
131</Flexbox>
132}
133open={open}
134overlayClassName={cx(className, styles.overlay)}
135overlayStyle={{ maxWidth, zIndex: 1000, ...style }}
136placement={placement}
137trigger="hover"
138>
139{children}
140</Popover>
141</div>
142</div>
143) : (
144children
145)}
146</ConfigProvider>
147);
148};
149
150export default TipGuide;
151