未验证 提交 9bef2157 编写于 作者: Y yangxiaolu1993 提交者: GitHub

feat:Popover功能补齐与单元测试 (#219)

上级 d57f997c
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react'
import '@testing-library/jest-dom'
import Popover from '../index'
import Button from '@/packages/button'
const itemList = [
{
name: '选项一',
},
{
name: '选项二',
},
{
name: '选项三',
},
]
const itemListDisabled = [
{
name: '选项一',
disabled: true,
},
{
name: '选项二',
disabled: true,
},
{
name: '选项三',
},
]
const iconItemList = [
{
name: '选项一',
icon: 'my2',
},
{
name: '选项二',
icon: 'cart2',
},
{
name: '选项三',
icon: 'location2',
},
]
test('render popover content', async () => {
const { container } = render(
<Popover visible list={itemList}>
<Button type="primary" shape="square">
明朗风格
</Button>
</Popover>
)
const content = container.querySelectorAll('.popover-content')[0]
expect(content.className).toContain(
'popover-content-show popover-content popover-content--bottom'
)
})
test('should emit onchoose event when clicking the action', async () => {
const choose = jest.fn()
const { container } = render(
<Popover visible list={itemList} onChoose={choose}>
<Button type="primary" shape="square">
明朗风格
</Button>
</Popover>
)
const contentItem = container.querySelectorAll('.popover-menu-item')[0]
fireEvent.click(contentItem)
await waitFor(() => expect(choose.mock.calls[0][0].name).toEqual('选项一'))
await waitFor(() => expect(choose.mock.calls[0][1]).toBe(0))
})
test('should not emit select event when the action is disabled', async () => {
const choose = jest.fn()
const { container } = render(
<Popover visible list={itemListDisabled} onChoose={choose}>
<Button type="primary" shape="square">
明朗风格
</Button>
</Popover>
)
const contentItem = container.querySelectorAll('.popover-menu-item')[0]
fireEvent.click(contentItem)
await waitFor(() => expect(choose).not.toBeCalled())
})
import React, { useState } from 'react'
import React, { useRef, useState } from 'react'
import { Popover } from './popover'
import Button from '@/packages/button'
import Icon from '@/packages/icon'
interface List {
name: string
icon?: string
disabled?: boolean
}
const BadgeDemo = () => {
const selfContentStyle = {
width: '195px',
......@@ -23,14 +29,7 @@ const BadgeDemo = () => {
fontSize: '10px',
textAlign: 'center',
} as any
const hTwo = {
marginTop: '30px',
marginBottom: '10px',
fontSize: '14px',
color: '#909ca4',
padding: '0 10px',
fontWeight: 400,
} as any
const itemList = [
{
name: '选项一',
......@@ -99,144 +98,183 @@ const BadgeDemo = () => {
const [darkTheme, setDarkTheme] = useState(false)
const [showIcon, setShowIcon] = useState(false)
const [disableAction, setDisableAction] = useState(false)
const [topLocation, setTopLocation] = useState(false)
const [rightLocation, setRightLocation] = useState(false)
const [leftLocation, setLeftLocation] = useState(false)
const [customized, setCustomized] = useState(false)
const customLocation = useRef([
{ bottom: false },
{ top: false },
{ left: false },
{ right: false },
{ 'top-start': false },
{ 'top-end': false },
{ 'bottom-start': false },
{ 'bottom-end': false },
{ 'left-start': false },
{ 'left-end': false },
{ 'right-start': false },
{ 'right-end': false },
])
const [customLocationName, setCustomLocationName] = useState('top')
const [customLocationShow, setCustomLocationShow] = useState(false)
const chooseHandle = (item: List, index: number) => {
console.log('选择')
}
const styles = `
.customButtonBox {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.brickBox {
display: flex;
justify-content: center;
margin: 80px 0;
}
.brick {
width: 60px;
height: 60px;
background: #1989fa;
border-radius: 10px;
}
.popover-content {
width: 100px;
}
.customContent .popover-content{
width: 200px;
}
`
return (
<>
<style>{styles}</style>
<div className="demo">
<div>
<h6 style={hTwo}>基础用法</h6>
<Popover
visible={lightTheme}
onClick={() => {
lightTheme ? setLightTheme(false) : setLightTheme(true)
}}
list={itemList}
>
<Button type="primary" shape="square">
明朗风格
</Button>
</Popover>
<Popover
visible={darkTheme}
theme="dark"
onClick={() => {
darkTheme ? setDarkTheme(false) : setDarkTheme(true)
}}
list={itemList}
>
<Button type="primary" shape="square">
暗黑风格
</Button>
</Popover>
</div>
<div>
<h6 style={hTwo}>选项配置</h6>
<Popover
visible={showIcon}
theme="dark"
onClick={() => {
showIcon ? setShowIcon(false) : setShowIcon(true)
}}
list={iconItemList}
>
<Button type="primary" shape="square">
展示图标
</Button>
</Popover>
<Popover
visible={disableAction}
onClick={() => {
disableAction ? setDisableAction(false) : setDisableAction(true)
}}
list={itemListDisabled}
>
<Button type="primary" shape="square">
禁用选项
</Button>
</Popover>
</div>
<div>
<h6 style={hTwo}>自定义内容</h6>
<Popover
visible={customized}
onClick={() => {
customized ? setCustomized(false) : setCustomized(true)
}}
>
<Button type="primary" shape="square">
自定义内容
</Button>
{customized ? (
<div className="self-content" style={selfContentStyle}>
{selfContent.map((item: any) => {
return (
<div
className="self-content-item"
style={selfContentItem}
key={item.name}
>
<Icon name={item.name} size="15" />
<div
className="self-content-desc"
style={selfContentDesc}
>
{item.desc}
</div>
<h2>基础用法</h2>
<Popover
visible={lightTheme}
onClick={() => {
lightTheme ? setLightTheme(false) : setLightTheme(true)
}}
list={itemList}
style={{ marginRight: '30px' }}
>
<Button type="primary" shape="square">
明朗风格
</Button>
</Popover>
<Popover
visible={darkTheme}
theme="dark"
onClick={() => {
darkTheme ? setDarkTheme(false) : setDarkTheme(true)
}}
list={itemList}
>
<Button type="primary" shape="square">
暗黑风格
</Button>
</Popover>
<h2>选项配置</h2>
<Popover
visible={showIcon}
theme="dark"
onClick={() => {
showIcon ? setShowIcon(false) : setShowIcon(true)
}}
list={iconItemList}
style={{ marginRight: '30px' }}
>
<Button type="primary" shape="square">
展示图标
</Button>
</Popover>
<Popover
visible={disableAction}
onClick={() => {
disableAction ? setDisableAction(false) : setDisableAction(true)
}}
list={itemListDisabled}
onChoose={chooseHandle}
>
<Button type="primary" shape="square">
禁用选项
</Button>
</Popover>
<h2>自定义内容</h2>
<Popover
visible={customized}
onClick={() => {
customized ? setCustomized(false) : setCustomized(true)
}}
location="bottom-start"
className="customContent"
>
<Button type="primary" shape="square">
自定义内容
</Button>
{customized ? (
<div className="self-content" style={selfContentStyle}>
{selfContent.map((item: any) => {
return (
<div
className="self-content-item"
style={selfContentItem}
key={item.name}
>
<Icon name={item.name} size="15" />
<div className="self-content-desc" style={selfContentDesc}>
{item.desc}
</div>
)
})}
</div>
) : (
''
)}
</Popover>
</div>
<div>
<h6 style={hTwo}>位置自定义</h6>
<Popover
visible={topLocation}
location="top"
theme="dark"
onClick={() => {
topLocation ? setTopLocation(false) : setTopLocation(true)
}}
list={iconItemList}
>
<Button type="primary" shape="square">
向上弹出
</Button>
</Popover>
{/* eslint-disable-next-line jsx-a11y/heading-has-content */}
<h2 style={hTwo} />
<Popover
visible={rightLocation}
location="right"
theme="dark"
onClick={() => {
rightLocation ? setRightLocation(false) : setRightLocation(true)
}}
list={iconItemList}
>
<Button type="primary" shape="square">
向右弹出
</Button>
</Popover>
<Popover
visible={leftLocation}
location="left"
theme="dark"
onClick={() => {
leftLocation ? setLeftLocation(false) : setLeftLocation(true)
}}
list={iconItemList}
>
<Button type="primary" shape="square">
向左弹出
</Button>
</Popover>
</div>
)
})}
</div>
) : (
''
)}
</Popover>
<h2 className="demoClass">位置自定义</h2>
<Popover
visible={customLocationShow}
location={customLocationName}
onClick={() => {
setCustomLocationShow(false)
}}
list={iconItemList}
onChoose={chooseHandle}
className="brickBox"
>
<div className="brick" />
</Popover>
<div className="customButtonBox">
{customLocation.current.map((location, i) => {
const k = Object.keys(location)[0] as any
const v = Object.values(location)[0]
return (
<Button
key={i}
type="primary"
shape="square"
style={{ width: '160px', marginBottom: '8px' }}
onClick={() => {
setCustomLocationName(k)
setCustomLocationShow(!customLocationShow)
}}
>
{k} 弹出
</Button>
)
})}
</div>
</div>
</>
......
......@@ -161,6 +161,26 @@ export default App;
:::
### 位置自定义
通过 location 属性来控制气泡的弹出位置。可选值
```
top # 顶部中间位置
left # 左侧中间位置
right # 右侧中间位置
bottom # 底部中间位置
```
`v1.2.3` 起新增
```
top-start # 顶部左侧位置
top-end # 顶部右侧位置
left-start # 左侧上方位置
left-end # 左侧下方位置
right-start # 右侧上方位置
right-end # 右侧下方位置
bottom-start # 底部左侧位置
bottom-end # 底部右侧位置
```
:::demo
```tsx
import React, { useState, useRef } from "react";
......@@ -186,22 +206,6 @@ const App = () => {
list={iconItemList}>
<Button type="primary" shape="square">向上弹出</Button>
</Popover>
<Popover
visible={rightLocation}
location="right"
theme="dark"
onClick={()=>{rightLocation ? setRightLocation(false) : setRightLocation(true)}}
list={iconItemList}>
<Button type="primary" shape="square">向右弹出</Button>
</Popover>
<Popover
visible={leftLocation}
location="left"
theme="dark"
onClick={()=>{leftLocation ? setLeftLocation(false) : setLeftLocation(true)}}
list={iconItemList}>
<Button type="primary" shape="square">向左弹出</Button>
</Popover>
</>
)
}
......@@ -219,7 +223,8 @@ export default App;
| list | 选项列表 | List[] | [] |
| visible | 是否展示气泡弹出层 | boolean | false |
| theme | 主题风格,可选值为 dark | string | `light` |
| location | 弹出位置,可选值为 top,left,right | string | `bottom` |
| location | 弹出位置 | string | `bottom` |
| offset `v1.2.3` | 出现位置的偏移量 | number | 20 |
### List 数据结构
......@@ -235,7 +240,8 @@ List 属性是一个由对象构成的数组,数组中的每个对象配置一
| 名称 | 说明 |
|---------|--------------|
| onClick | 打开(关闭)菜单时触发 |
| onClick | 点击菜单时触发 |
| onChoose | 点击选项时触发 |
@import '../icon/icon.scss';
.popBox {
// background: skyblue;
// // background: #fff;
// padding: 20px;
.titBox {
// margin-bottom: 20px;
}
}
.nut-popover--dark,
.nut-popover {
position: relative;
display: inline-block;
margin-right: 20px;
> div {
position: relative;
// z-index: 9999;
}
.more-background {
background: $popover-white-background-color;
opacity: 0;
......@@ -21,10 +17,163 @@
z-index: 10;
left: 0;
}
.popoverContent--left,
.popoverContent--right,
.popoverContent--top,
.popoverContent {
.popover-arrow {
position: absolute;
width: 0;
height: 0;
border: 8px solid transparent;
}
// top
.popover-arrow-top {
bottom: 0;
border-top-color: $popover-white-background-color;
border-bottom-width: 0;
margin-bottom: -8px;
}
.popover-content--top {
left: 50%;
transform: translateX(-50%);
.popover-arrow--top {
left: 50%;
transform: translateX(-50%);
}
}
.popover-content--top-end {
.popover-arrow--top-end {
right: 16px;
transform: translateX(0%);
}
right: 0;
}
.popover-content--top-start {
left: 0;
.popover-arrow--top-start {
left: 16px;
transform: translateX(0%);
}
}
// bottom
.popover-content--bottom {
left: 50%;
transform: translateX(-50%);
}
.popover-content--bottom-end {
right: 0;
}
.popover-content--bottom-start {
left: 0;
}
// left
.popover-content--left {
top: 50%;
transform: translateY(-50%);
}
.popover-content--left-end {
bottom: 0;
}
.popover-content--left-start {
top: 0;
}
// right
.popover-content--right {
top: 50%;
transform: translateY(-50%);
}
.popover-content--right-end {
bottom: 0;
}
.popover-content--right-start {
top: 0;
}
// arrow bottom
.popover-arrow-bottom {
top: 0px;
border-bottom-color: $popover-white-background-color;
border-top-width: 0;
margin-top: -8px;
}
.popover-arrow--bottom {
left: 50%;
transform: translateX(-50%);
}
.popover-arrow--bottom-start {
left: 16px;
transform: translateX(0%);
}
.popover-arrow--bottom-end {
right: 16px;
transform: translateX(0%);
}
// arrow left
.popover-arrow-left {
right: 0px;
border-left-color: $popover-white-background-color;
border-right-width: 0;
margin-right: -8px;
}
.popover-arrow--left {
top: 50%;
transform: translateY(-50%);
}
.popover-arrow--left-start {
top: 16px;
transform: translateY(0%);
}
.popover-arrow--left-end {
bottom: 16px;
transform: translateY(0%);
}
// arrow right
.popover-arrow-right {
left: 0px;
border-right-color: $popover-white-background-color;
border-left-width: 0;
margin-left: -8px;
}
.popover-arrow--right {
top: 50%;
transform: translateY(-50%);
}
.popover-arrow--right-start {
top: 16px;
transform: translateY(0%);
}
.popover-arrow--right-end {
bottom: 16px;
transform: translateY(0%);
}
.popover-content {
z-index: 12;
background: $popover-white-background-color;
border-radius: 5px;
......@@ -34,63 +183,37 @@
font-weight: normal;
color: $popover-primary-text-color;
position: absolute;
.popoverArrow {
position: absolute;
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 10px solid transparent;
border-bottom: 10px solid $popover-white-background-color;
box-shadow: 0 2px 12px #3232331f;
opacity: 0;
transition: opacity 0.1s;
&.popover-content-show {
opacity: 1;
}
.title-item {
.popover-menu-item {
display: flex;
align-items: center;
padding-bottom: 8px;
margin: 8px;
border-bottom: 1px solid $popover-border-bottom-color;
&:first-child {
margin-top: 15px;
}
&:last-child {
margin-bottom: 2px;
border-bottom: none;
}
.title-name {
.popover-menu-item-name {
margin-right: 12px;
margin-left: 8px;
width: 100%;
}
}
}
.popoverContent--top {
.popoverArrow--top {
position: absolute;
top: auto;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 10px solid $popover-white-background-color;
border-bottom: 10px solid transparent;
}
}
.popoverContent--left {
.popoverArrow--left {
position: absolute;
border-left: 10px solid $popover-white-background-color;
border-right: 10px solid transparent;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
}
.popoverContent--right {
.popoverArrow--right {
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid $popover-white-background-color;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
}
.disabled {
color: $popover-disable-color;
......@@ -101,42 +224,41 @@
.nut-popover--dark {
background: $popover-dark-background-color;
color: $popover-white-background-color;
.popoverContent--left,
.popoverContent--right,
.popoverContent--top,
.popoverContent {
background: $popover-dark-background-color;
color: $popover-white-background-color;
.popoverArrow {
border-bottom: 10px solid $popover-dark-background-color;
.popover-content {
background: $popover-dark-background-color !important;
color: $popover-white-background-color !important;
}
.popover-content--bottom,
.popover-content--bottom-start,
.popover-content--bottom-end {
.popover-arrow {
border-bottom-color: $popover-dark-background-color;
}
}
.popoverContent--top {
.popoverArrow--top {
position: absolute;
top: auto;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 10px solid $popover-dark-background-color;
border-bottom: 10px solid transparent;
.popover-content--top,
.popover-content--top-start,
.popover-content--top-end {
.popover-arrow {
border-top-color: $popover-dark-background-color;
}
}
.popoverContent--left {
.popoverArrow--left {
position: absolute;
border-left: 10px solid $popover-dark-background-color;
border-right: 10px solid transparent;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
.popover-content--left,
.popover-content--left-start,
.popover-content--left-end {
.popover-arrow {
border-left-color: $popover-dark-background-color;
}
}
.popoverContent--right {
.popoverArrow--right {
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid $popover-dark-background-color;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
.popover-content--right,
.popover-content--right-start,
.popover-content--right-end {
.popover-arrow {
border-right-color: $popover-dark-background-color;
}
}
}
......@@ -5,73 +5,90 @@ import React, {
useRef,
useState,
} from 'react'
import ReactDOM from 'react-dom'
import Trigger from './Trigger'
import Icon from '@/packages/icon'
import Overlay from '@/packages/overlay'
export type PopoverTheme = 'light' | 'dark'
export type PopoverLocation =
| 'bottom'
| 'top'
| 'left'
| 'right'
| 'top-start'
| 'top-end'
| 'bottom-start'
| 'bottom-end'
| 'left-start'
| 'left-end'
| 'right-start'
| 'right-end'
export interface List {
name: string
icon?: string
disabled?: boolean
}
export interface PopoverProps {
list: Array<any>
theme: string
location: string
list: List[]
theme: PopoverTheme
location: PopoverLocation | string
visible: boolean
offset: string | number
className: string
style?: CSSProperties
onClick: (e: MouseEvent) => void
children?: React.ReactNode
onClick: (e: React.MouseEvent) => void
onChoose: (item: List, index: number) => void
}
export function findDOMNode<T = HTMLElement>(
node: React.ReactInstance | HTMLElement
): T {
if (node instanceof HTMLElement) {
return node as unknown as T
}
// eslint-disable-next-line react/no-find-dom-node
return ReactDOM.findDOMNode(node) as unknown as T
}
const getEleAttr = (ele: HTMLElement | Element) => {
if (ele && ele.getBoundingClientRect) {
return ele.getBoundingClientRect()
}
return null
}
export type PopoverType =
| 'default'
| 'primary'
| 'success'
| 'warning'
| 'danger'
const defaultProps = {
list: [],
theme: 'light',
location: 'bottom',
visible: false,
offset: 20,
className: '',
onClick: (e: MouseEvent) => {},
onClick: (e: React.MouseEvent) => {},
onChoose: (item, index) => {},
} as PopoverProps
export const Popover: FunctionComponent<Partial<PopoverProps>> = (props) => {
export const Popover: FunctionComponent<
Partial<PopoverProps> & React.HTMLAttributes<HTMLDivElement>
> = (props) => {
const {
children,
list,
theme,
location,
visible,
offset,
className,
style,
onClick,
onChoose,
...reset
} = {
...defaultProps,
...props,
}
const goodItem = useRef(null)
// eslint-disable-next-line react/no-find-dom-node
const aa = goodItem.current && findDOMNode(goodItem.current)
setTimeout(() => {
if (aa) {
setElWidth((getEleAttr(aa) as any).width)
setElHeight((getEleAttr(aa) as any).height)
if (goodItem.current && getEleAttr(goodItem.current)) {
setElWidth((getEleAttr(goodItem.current) as any).width)
setElHeight((getEleAttr(goodItem.current) as any).height)
}
})
const [classes, setClasses] = useState('')
const [elWidth, setElWidth] = useState(0)
const [elHeight, setElHeight] = useState(0)
......@@ -83,101 +100,107 @@ export const Popover: FunctionComponent<Partial<PopoverProps>> = (props) => {
setPopoverArrow(popoverArrowSelf())
}, [list, theme])
const getStyle = () => {
const offNumer = Number(offset) ? Number(offset) : 0
const style: CSSProperties = {}
if (location === 'top') {
style.bottom = elHeight + 20
style.left = 0
} else if (location === 'right') {
style.top = 0
style.right = -elWidth - 20
} else if (location === 'left') {
style.top = 0
style.left = -elWidth - 20
} else {
style.top = elHeight + 20
style.left = 0
}
style.top += 'px'
style.left += 'px'
style.bottom += 'px'
style.right += 'px'
return style
}
const getArrowStyle = () => {
const style: CSSProperties = {}
if (location === 'top') {
style.bottom = -20
style.left = elWidth / 2
} else if (location === 'right') {
style.top = 20
style.left = -20
} else if (location === 'left') {
style.top = 20
style.right = -20
if (location.includes('top')) {
style.bottom = `${elHeight + offNumer}px`
} else if (location.includes('right')) {
style.left = `${elWidth + offNumer}px`
} else if (location.includes('left')) {
style.right = `${elWidth + offNumer}px`
} else {
style.left = elWidth / 2
style.top = -20
style.top = `${elHeight + offNumer}px`
}
style.top += 'px'
style.left += 'px'
style.bottom += 'px'
style.right += 'px'
return style
}
const classesSelf = () => {
const prefixCls = 'nut-popover'
return `${prefixCls}
${theme ? `${prefixCls}--${theme}` : ''}`
return `${prefixCls} ${theme ? `${prefixCls}--${theme}` : ''}`
}
const popoverContentSelf = () => {
const prefixCls = 'popoverContent'
return `${prefixCls}
${location ? `${prefixCls}--${location}` : ''}`
const prefixCls = 'popover-content'
return `${prefixCls}-show ${prefixCls} ${
location ? `${prefixCls}--${location}` : ''
}`
}
const filter = () => {
const ms = ['top', 'bottom', 'left', 'right']
return ms.filter((m) => location.includes(m))[0]
}
const popoverArrowSelf = () => {
const prefixCls = 'popoverArrow'
return `${prefixCls}
${location ? `${prefixCls}--${location}` : ''}`
const prefixCls = 'popover-arrow'
return `${prefixCls} ${prefixCls}-${filter()} ${
location ? `${prefixCls}--${location}` : ''
}`
}
// const showPopup = props.visible
const handleClick = (e: any) => {
const handleClick = (e: React.MouseEvent) => {
if (props.onClick) {
props.onClick(e)
}
}
const handleChoose = (item: List, index: number) => {
if (!item.disabled) {
onChoose(item, index)
}
}
return (
<div className={`${classes} ${className}`} style={{ ...style }} {...reset}>
<Trigger forwardedRef={goodItem}>
<div onClick={(e) => handleClick(e)}>
{Array.isArray(children) ? children[0] : children}
{visible ? (
<div className={`${popoverContent}`} style={getStyle()}>
<div className={`${popoverArrow}`} style={getArrowStyle()}>
{' '}
<>
<div
className={`${classes} ${className}`}
style={{ ...style }}
{...reset}
>
<Trigger forwardedRef={goodItem}>
<div onClick={(e) => handleClick(e)}>
{Array.isArray(children) ? children[0] : children}
{visible ? (
<div className={`${popoverContent}`} style={getStyle()}>
<div className={`${popoverArrow}`} />
{Array.isArray(children) ? children[1] : ''}
{list.map((item: List, i: number) => {
return (
<div
key={item.name}
className={`popover-menu-item ${
item.disabled ? 'disabled' : ''
}`}
onClick={() => {
handleChoose(item, i)
}}
>
{item.icon ? (
<Icon
className="popover-menu-item-img"
name={item.icon}
/>
) : (
''
)}
<div className="popover-menu-item-name">{item.name}</div>
</div>
)
})}
</div>
{Array.isArray(children) ? children[1] : ''}
{list.map((item) => {
return (
<div
key={item.name}
className={`title-item ${item.disabled ? 'disabled' : ''}`}
>
{item.icon ? (
<Icon className="item-img" name={item.icon} />
) : (
''
)}
<div className="title-name">{item.name}</div>
</div>
)
})}
</div>
) : null}
</div>
</Trigger>
</div>
) : null}
</div>
</Trigger>
</div>
{visible ? (
<Overlay
visible={visible}
onClick={(e) => handleClick(e)}
style={{ background: 'transparent' }}
/>
) : (
''
)}
</>
)
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册