ソースを参照

fix: [avatar] fix onClick, onMouseEnter, onMouseLeave do not call when Avatar has border/topSlot/bottomSlot

zhangyumei.0319 1 年間 前
コミット
f611109f4c

+ 2 - 2
content/show/avatar/index-en-US.md

@@ -429,7 +429,7 @@ import { Avatar, AvatarGroup } from '@douyinfe/semi-ui';
 | ------------ |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -------- |
 | alt          | Defines an alternative text description of the image.                                                                                                                                     | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | -        |
 | border | additional border(>=2.52.0)                                                                                                                                                               | {color?:string //color, motion?:boolean // has animation} or boolean                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | - |
-| bottomSlot | bottom Slot config (>= 2.52.0 )                                                                                                                                                           | {<br/><div style={{width:20,display:'inline-block'}}/>render?: () => React.ReactNode //Full control the rendering,<br/><div style={{width:20,display:'inline-block'}}/>shape?: "circle" or "square" // slot shape,<br/><div style={{width:20,display:'inline-block'}}/>content: React.ReactNode // slot content,<br/><div style={{width:20,display:'inline-block'}}/>bgColor:string // slot background <br/><div style={{width:20,display:'inline-block'}}/>textColor:string // text color <br/><div style={{width:20,display:'inline-block'}}/>className:string <br/><div style={{width:20,display:'inline-block'}}/>style?:CSSProperties<br/>}                                    | - |
+| bottomSlot | bottom Slot config (>= 2.52.0 )                                                                                                                                                           | {<br/><div style={{width:20,display:'inline-block'}}/>render?: () => React.ReactNode //Full control the rendering,<br/><div style={{width:20,display:'inline-block'}}/>shape?: "circle" or "square" // slot shape,<br/><div style={{width:20,display:'inline-block'}}/>text: React.ReactNode // slot content,<br/><div style={{width:20,display:'inline-block'}}/>bgColor:string // slot background <br/><div style={{width:20,display:'inline-block'}}/>textColor:string // text color <br/><div style={{width:20,display:'inline-block'}}/>className:string <br/><div style={{width:20,display:'inline-block'}}/>style?:CSSProperties<br/>}                                    | - |
 | className    | Class name                                                                                                                                                                                | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | -        |
 | color        | Color of the avatar, one of `amber`, `blue`, `cyan`, `green`, `grey`, `indigo`, `light-blue`, `light-green`, `lime`, `orange`, `pink`, `rain`, `red`, `teal`, `violet`, `yellow`, `white` | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | `grey`   |
 | contentMotion | avatar content area animation (>=2.xx.0)                                                                                                                                                  | boolean                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | - |
@@ -441,7 +441,7 @@ import { Avatar, AvatarGroup } from '@douyinfe/semi-ui';
 | src          | Resource address for imgage avatars                                                                                                                                                       | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | -        |
 | srcSet       | Set the image avatar responsive resource address                                                                                                                                          | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | -        |
 | style        | Style name                                                                                                                                                                                | CSSProperties                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | -        |
-| topSlot | top Slot config (>= 2.52.0 )                                                                                                                                                              | {<br/><div style={{width:20,display:'inline-block'}}/>render?: () => React.ReactNode //Full control the rendering,<br/> <div style={{width:20,display:'inline-block'}}/>gradientStart?: string // Top background gradient starting color <br/> <div style={{width:20,display:'inline-block'}}/>gradientEnd?: string // Top background gradient ending color<br/> <div style={{width:20,display:'inline-block'}}/>content: React.ReactNode <br/> <div style={{width:20,display:'inline-block'}}/>textColor:string //text color <br/> <div style={{width:20,display:'inline-block'}}/>className:string<br/><div style={{width:20,display:'inline-block'}}/>style?:CSSProperties<br/>} | - |
+| topSlot | top Slot config (>= 2.52.0 )                                                                                                                                                              | {<br/><div style={{width:20,display:'inline-block'}}/>render?: () => React.ReactNode //Full control the rendering,<br/> <div style={{width:20,display:'inline-block'}}/>gradientStart?: string // Top background gradient starting color <br/> <div style={{width:20,display:'inline-block'}}/>gradientEnd?: string // Top background gradient ending color<br/> <div style={{width:20,display:'inline-block'}}/>text: React.ReactNode <br/> <div style={{width:20,display:'inline-block'}}/>textColor:string //text color <br/> <div style={{width:20,display:'inline-block'}}/>className:string<br/><div style={{width:20,display:'inline-block'}}/>style?:CSSProperties<br/>} | - |
 | onClick      | Click the callback of the avatar.                                                                                                                                                         | (e: Event) => void                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | -        |
 | onError      | Image load failed event, returning false closes the default fallback behavior of the component                                                                                            | (e: Event) = > boolean                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | -        |
 | onMouseEnter | Callback to onMouseEnter event                                                                                                                                                            | (e: Event) => void                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | -        |

+ 2 - 2
content/show/avatar/index.md

@@ -424,7 +424,7 @@ import { AvatarGroup, Avatar } from '@douyinfe/semi-ui';
 | --- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| --- |
 | alt | 图像的替代文本描述                                                                                                                                                         | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | - |
 | border | 额外边框 (>=2.52.0)                                                                                                                                                   | {color?:string //颜色, motion?:boolean //是否开启动画} or boolean                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | - |
-| bottomSlot | 底部 Slot 配置 (>= 2.52.0 )                                                                                                                                           | {<br/><div style={{width:20,display:'inline-block'}}/>render?: () => React.ReactNode //完全控制渲染,<br/> <div style={{width:20,display:'inline-block'}}/>shape?: "circle" or "square" // Slot 形状,<br/> <div style={{width:20,display:'inline-block'}}/>content: React.ReactNode // Slot 内容,<br/> <div style={{width:20,display:'inline-block'}}/>bgColor:string // Slot 背景色 <br/> <div style={{width:20,display:'inline-block'}}/>textColor:string // 文字颜色 <br/> <div style={{width:20,display:'inline-block'}}/>className:string <br/> <div style={{width:20,display:'inline-block'}}/>style?:CSSProperties<br/>} | - |
+| bottomSlot | 底部 Slot 配置 (>= 2.52.0 )                                                                                                                                           | {<br/><div style={{width:20,display:'inline-block'}}/>render?: () => React.ReactNode //完全控制渲染,<br/> <div style={{width:20,display:'inline-block'}}/>shape?: "circle" or "square" // Slot 形状,<br/> <div style={{width:20,display:'inline-block'}}/>text: React.ReactNode // Slot 内容,<br/> <div style={{width:20,display:'inline-block'}}/>bgColor:string // Slot 背景色 <br/> <div style={{width:20,display:'inline-block'}}/>textColor:string // 文字颜色 <br/> <div style={{width:20,display:'inline-block'}}/>className:string <br/> <div style={{width:20,display:'inline-block'}}/>style?:CSSProperties<br/>} | - |
 | className | 类名                                                                                                                                                                | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | - |
 | color | 指定头像的颜色,支持 `amber`、 `blue`、 `cyan`、 `green`、 `grey`、 `indigo`、 `light-blue`、 `light-green`、 `lime`、 `orange`、 `pink`、 `purple`、 `red`、 `teal`、 `violet`、 `yellow` | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | `grey` |
 | contentMotion | 头像内容区域动效 (>=2.xx.0)                                                                                                                                               | boolean                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | - |
@@ -436,7 +436,7 @@ import { AvatarGroup, Avatar } from '@douyinfe/semi-ui';
 | src | 图片类头像的资源地址                                                                                                                                                        | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | - |
 | srcSet | 设置图片类头像响应式资源地址                                                                                                                                                    | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | - |
 | style | 样式名                                                                                                                                                               | CSSProperties                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | - |
-| topSlot | 顶部 Slot 配置 (>= 2.52.0 )                                                                                                                                           | {<br/> <div style={{width:20,display:'inline-block'}}/>render?: () => React.ReactNode //完全控制渲染,<br/> <div style={{width:20,display:'inline-block'}}/>gradientStart?: string // 顶部背景渐变起始色<br/> <div style={{width:20,display:'inline-block'}}/>gradientEnd?: string // 顶部背景渐变结束色<br/> <div style={{width:20,display:'inline-block'}}/>content: React.ReactNode <br/> <div style={{width:20,display:'inline-block'}}/>textColor:string //文字颜色 <br/> <div style={{width:20,display:'inline-block'}}/>className:string<br/><div style={{width:20,display:'inline-block'}}/>style?:CSSProperties<br/>}             | - |
+| topSlot | 顶部 Slot 配置 (>= 2.52.0 )                                                                                                                                           | {<br/> <div style={{width:20,display:'inline-block'}}/>render?: () => React.ReactNode //完全控制渲染,<br/> <div style={{width:20,display:'inline-block'}}/>gradientStart?: string // 顶部背景渐变起始色<br/> <div style={{width:20,display:'inline-block'}}/>gradientEnd?: string // 顶部背景渐变结束色<br/> <div style={{width:20,display:'inline-block'}}/>text: React.ReactNode <br/> <div style={{width:20,display:'inline-block'}}/>textColor:string //文字颜色 <br/> <div style={{width:20,display:'inline-block'}}/>className:string<br/><div style={{width:20,display:'inline-block'}}/>style?:CSSProperties<br/>}             | - |
 | onClick | 单击头像的回调                                                                                                                                                           | (e: Event) => void                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | - |
 | onError | 图片加载失败的事件,返回 false 会关闭组件默认的 fallback 行为                                                                                                                           | (e: Event) => boolean                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | - |
 | onMouseEnter | MouseEnter 事件的回调                                                                                                                                                  | (e: Event) => void                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | - |

+ 24 - 0
packages/semi-ui/avatar/__test__/avatar.test.js

@@ -346,6 +346,14 @@ describe('Avatar', () => {
         expect(spyOnClick.calledOnce).toBe(true);
     })
 
+    it('onClick, topSlot', () => {
+        const onClick = () => {};
+        const spyOnClick = sinon.spy(onClick); 
+        const avatar = mount(<Avatar onClick={spyOnClick} topSlot={{ text: '直播' }}/>);
+        avatar.simulate('click');
+        expect(spyOnClick.calledOnce).toBe(true);
+    })
+
     it('onMouseEnter', () => {
         const onMouseEnter = () => {};
         const spyOnMouseEnter = sinon.spy(onMouseEnter); 
@@ -354,6 +362,14 @@ describe('Avatar', () => {
         expect(spyOnMouseEnter.calledOnce).toBe(true);
     })
 
+    it('onMouseEnter, topSlot', () => {
+        const onMouseEnter = () => {};
+        const spyOnMouseEnter = sinon.spy(onMouseEnter); 
+        const avatar = mount(<Avatar onMouseEnter={spyOnMouseEnter} topSlot={{ text: '直播' }} /> );
+        avatar.simulate('mouseEnter');
+        expect(spyOnMouseEnter.calledOnce).toBe(true);
+    })
+
     it('onMouseLeave', () => {
         const onMouseLeave = () => {};
         const spyOnMouseLeave = sinon.spy(onMouseLeave); 
@@ -362,6 +378,14 @@ describe('Avatar', () => {
         expect(spyOnMouseLeave.calledOnce).toBe(true);
     })
 
+    it('onMouseLeave, topSlot', () => {
+        const onMouseLeave = () => {};
+        const spyOnMouseLeave = sinon.spy(onMouseLeave); 
+        const avatar = mount(<Avatar onMouseLeave={spyOnMouseLeave} topSlot={{ text: '直播' }} />);
+        avatar.simulate('mouseLeave');
+        expect(spyOnMouseLeave.calledOnce).toBe(true);
+    })
+
     it('hoverMask', () => {
         const avatar = mount(<Avatar hoverMask='asd' />);
         expect(avatar.simulate('mouseEnter', {}).exists(`.${avartarPrefix}-hover`)).toEqual(true);

+ 36 - 32
packages/semi-ui/avatar/_story/avatar.stories.jsx

@@ -43,27 +43,31 @@ export const BottomSolt = () => (
         <div>
             <Avatar shape="circle" border={true} bottomSlot={{
                 shape:'circle',
-                content:<IconPlus/>
-            }}>U</Avatar>
+                text:<IconPlus/>
+            }}
+            onClick={(e) => {console.log('on click')}}
+            onMouseEnter={(e) => {console.log('on mouse enter')}}
+            onMouseLeave={(e) => {console.log('onMouse leave')}}
+            >U</Avatar>
             <Avatar shape="circle" size={'large'} border={true} bottomSlot={{
                 shape:'circle',
-                content:<IconPlus/>
+                text:<IconPlus/>
             }}>U</Avatar>
             <Avatar shape="circle" size={'small'} border={true} bottomSlot={{
                 shape:'circle',
-                content:<IconPlus/>
+                text:<IconPlus/>
             }}>U</Avatar>
             <Avatar shape="circle" bottomSlot={{
                 shape:'square',
-                content: "直播中"
+                text: "直播中"
             }}>U</Avatar>
             <Avatar shape="circle" size={"large"} bottomSlot={{
                 shape:'square',
-                content: "直播中"
+                text: "直播中"
             }}>U</Avatar>
             <Avatar shape="circle" bottomSlot={{
                 shape:'rect',
-                content: "直播中",
+                text: "直播中",
                 render:()=>{
                     return "test"
                 }
@@ -76,80 +80,80 @@ export const TopSolt = () => (
     <div>
         <div>
             <Avatar shape="circle"  size={"extra-extra-small"}  border={true} topSlot={{
-                content:"直播",
+                text:"直播",
                 gradientStart:"rgb(255,23,100)",
                 gradientEnd:"rgb(237,52,148)"
             }}>U</Avatar>
             <Avatar shape="circle"  size={"extra-small"}  border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square" size={"default"} border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="circle" size={"medium"} border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="circle" size={"large"} borderMotion={true} border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }} bottomSlot={{
-                content:"T",
+                text:"T",
                 shape:"circle"
             }} contentMotion={true}>U</Avatar>
             <br/>
             <Avatar shape="square"  size={"extra-extra-small"}  border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square"  size={"extra-small"}  border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square" size={"default"} border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square" size={"medium"} border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square" size={"large"} borderMotion={true} border={true} topSlot={{
-                content:"直播"
+                text:"直播"
             }}  bottomSlot={{
-                content:"T",
+                text:"T",
                 shape:"circle"
             }}>U</Avatar>
             <br/>
             <Avatar shape="circle"  size={"extra-extra-small"}  border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="circle"  size={"extra-small"}  border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square" size={"default"} border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="circle" size={"medium"} border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="circle" size={"large"} borderMotion={true} border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}  bottomSlot={{
-                content:"T",
+                text:"T",
                 shape:"circle"
             }}>U</Avatar>
             <br/>
             <Avatar shape="square"  size={"extra-extra-small"}  border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square"  size={"extra-small"}  border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square" size={"default"} border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square" size={"medium"} border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}>U</Avatar>
             <Avatar shape="square" size={"large"} borderMotion={true} border={false} topSlot={{
-                content:"直播"
+                text:"直播"
             }}  bottomSlot={{
-                content:"T",
+                text:"T",
                 shape:"circle"
             }}>U</Avatar>
         </div>
@@ -176,7 +180,7 @@ export const GroupSize = () => (
   <div>
     <p>medium</p>
     <AvatarGroup>
-      <Avatar color="red" topSlot={{content:"T"}} bottomSlot={{content:"T"}}>LL</Avatar>
+      <Avatar color="red" topSlot={{text:"T"}} bottomSlot={{text:"T"}}>LL</Avatar>
       <Avatar>CX</Avatar>
       <Avatar size="default">CX</Avatar>
       <Avatar color="amber">RM</Avatar>

+ 10 - 6
packages/semi-ui/avatar/index.tsx

@@ -336,6 +336,12 @@ export default class Avatar extends BaseComponent<AvatarProps, AvatarState> {
             ...others
         } = this.props;
         const { isImgExist, hoverContent, focusVisible } = this.state;
+        const shouldWrap = bottomSlot || topSlot || border;
+        const mouseEvent = {
+            onClick: onClick,
+            onMouseEnter: this.onEnter,
+            onMouseLeave: this.onLeave,
+        };
         const isImg = src && isImgExist;
         const avatarCls = cls(
             prefixCls,
@@ -355,11 +361,9 @@ export default class Avatar extends BaseComponent<AvatarProps, AvatarState> {
 
         let avatar = <span
             {...(others as any)}
-            style={(border || bottomSlot || topSlot || border) ? {} : style}
+            style={shouldWrap ? {} : style}
             className={avatarCls}
-            onClick={onClick as any}
-            onMouseEnter={this.onEnter as any}
-            onMouseLeave={this.onLeave as any}
+            {...(shouldWrap ? {} : mouseEvent)}
             role='listitem'
             ref={this.avatarRef}>
             {this.getContent()}
@@ -397,8 +401,8 @@ export default class Avatar extends BaseComponent<AvatarProps, AvatarState> {
         }
 
 
-        if (bottomSlot || topSlot || border) {
-            return <span className={cls([`${prefixCls}-wrapper`])} style={style}>
+        if (shouldWrap) {
+            return <span className={cls([`${prefixCls}-wrapper`])} style={style} {...mouseEvent}>
                 {avatar}
                 {topSlot && ["small", "default", "medium", "large", "extra-large"].includes(size) && shape === "circle" && this.renderTopSlot()}
                 {bottomSlot && ["small", "default", "medium", "large", "extra-large"].includes(size) && this.renderBottomSlot()}