Browse Source

Feat click out side (#273)

* feat: [tooltip] Tooltip/Popover/Popconfirm support onClickOutSide, #268

* docs: update onClickOutSide support version
pointhalo 3 years ago
parent
commit
b6ce00f945

+ 1 - 1
content/feedback/popconfirm/index-en-US.md

@@ -148,6 +148,6 @@ Please refer to [Use with Tooltip/Popover](/en-US/show/tooltip#Use-with-Popver-o
 | onConfirm          | Click the confirmation button to call back.                                                                                                                           | (e) => void                |                     |
 | onCancel           | Click the Cancel button to call back.                                                                                                                                 | (e) => void                |                     |
 | onVisibleChange    | Bubble box toggle shows hidden callbacks                                                                                                                              | (visible: boolean) => void | () => {}            | **0.19.0**        |
-
+| onClickOutSide     | Callback when the pop-up layer is in the display state and the non-Children, non-floating layer inner area is clicked                                                 | (e: event) => void         |                     | **2.1.0**        |
 ## Design Tokens
 <DesignToken/>

+ 1 - 0
content/feedback/popconfirm/index.md

@@ -145,6 +145,7 @@ function TypesConfirmDemo(props = {}) {
 | zIndex             | 浮层 z-index 值                                                                                                                             | number                           | 1030                |
 | onConfirm          | 点击确认按钮回调                                                                                                                            | Function(e)                      |                     |
 | onCancel           | 点击取消按钮回调                                                                                                                            | Function(e)                      |                     |
+| onClickOutSide     | 当弹出层处于展示状态,点击非Children、非浮层内部区域时的回调                                                                                      | Function(e)                      |  **2.1.0**      |
 | onVisibleChange    | 气泡框切换显示隐藏的回调                                                                                                               | Function(visible: boolean): void | () => {}            | **0.19.0**        |
 
 ## 设计变量

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

@@ -463,7 +463,6 @@ Please refer to [Use with Tooltip/Popconfirm](/en-US/show/tooltip#%E6%90%AD%E9%8
 | getPopupContainer | Specifies the parent DOM, and the bullet layer will be rendered to the DOM, you need to set 'position: relative` | () => HTMLElement | () => document.body |
 | mouseEnterDelay | After the mouse is moved in, the display delay time, in milliseconds (only effective when the trigger is hover/focus) | number | 50 |  |
 | mouseLeaveDelay | The time for the delay to disappear after the mouse is moved out, in milliseconds (only effective when the trigger is hover/focus) | number | 50 |  |
-| onVisibleChange | A callback triggered when the pop-up layer is displayed / hidden | (isVisble: boolean) => void |  |
 | rePosKey | You can update the value of this item to manually trigger the repositioning of the pop-up layer | string\|number |  |  |
 | visible | Display popup or not | boolean |  |
 | position | Directions, optional values: `top`, `topLeft`, `topRight`, `leftTop`, `leftBottom`, `rightTop`, `rightTop`, `rightBottom`, `bottomLeft`, `bottomRight`, `bottomRight` | string | "bottom" |
@@ -472,7 +471,8 @@ Please refer to [Use with Tooltip/Popconfirm](/en-US/show/tooltip#%E6%90%AD%E9%8
 | trigger | Trigger mode, optional value: `hover`, `focus`, `click`, `custom` | string | 'hover' |
 | stopPropagation | Whether to prevent click events on the bomb layer from bubbling | boolean | false | **0.34.0** |
 | zIndex | Floating layer z-index value | number | 1030 |
-
+| onVisibleChange | A callback triggered when the pop-up layer is displayed / hidden | (isVisble: boolean) => void |  |
+| onClickOutSide  | Callback when the pop-up layer is in the display state and the non-Children, non-floating layer inner area is clicked (only valid when trigger is custom, click) | (e:event) => void | | **2.1.0** |
 ## Design Tokens
 
 <DesignToken/>

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

@@ -463,7 +463,6 @@ function Demo() {
 | getPopupContainer  | 指定父级 DOM,弹层将会渲染至该 DOM 中,自定义需要设置 `position: relative`                                                                  | function():HTMLElement     | () => document.body                         |            |
 | mouseEnterDelay    | 鼠标移入后,延迟显示的时间,单位毫秒(仅当 trigger 为 hover/focus 时生效)                                                                  | number                     | 50                                          |            |
 | mouseLeaveDelay    | 鼠标移出后,延迟消失的时间,单位毫秒(仅当 trigger 为 hover/focus 时生效)                                                                  | number                     | 50                                          |            |
-| onVisibleChange    | 弹出层展示/隐藏时触发的回调                                                                                                                 | function(isVisble:boolean) |                                             |            |
 | rePosKey           | 可以更新该项值手动触发弹出层的重新定位                                                                                                         | string\|number             |                                            |             |
 | position           | 方向,可选值:`top`,`topLeft`,`topRight`,`left`,`leftTop`,`leftBottom`,`right`,`rightTop`,`rightBottom`,`bottom`,`bottomLeft`,`bottomRight` | string                     | "bottom"                                    |            |
 | spacing            | 弹出层与 children 元素的距离,单位 px                                                                                                       | number                     | 4(showArrow=false 时) 10(showArrow=true 时) |            |
@@ -472,6 +471,7 @@ function Demo() {
 | trigger            | 触发方式,可选值:`hover`, `focus`, `click`, `custom`                                                                                       | string                     | 'hover'                                     |            |
 | visible            | 是否显示,配合trigger='custom'可实现完全受控                                                                                                                                    | boolean                    |                                             |            |
 | zIndex             | 弹出层 z-index 值                                                                                                                             | number                     | 1030                                        |            |
-
+| onVisibleChange    | 弹出层展示/隐藏时触发的回调                                                                                                                 | function(isVisble:boolean) |                                             |            |
+| onClickOutSide     | 当弹出层处于展示状态,点击非Children、非浮层内部区域时的回调(仅trigger为custom、click时有效)| function(e:event) |  | **2.1.0** |
 ## 设计变量
 <DesignToken/>

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

@@ -384,7 +384,7 @@ import { Popconfirm, Tooltip, Button } from '@douyinfe/semi-ui';
 | clickToHide         | Whether to automatically close the elastic layer when clicking on the floating layer and any element inside                                                                                                                                  | boolean                     | false               | **0.24.0** |
 | getPopupContainer   | Specifies the parent DOM, and the bullet layer will be rendered to the DOM                                                                                                                                                                   | () => HTMLElement           | () => document.body |
 | mouseEnterDelay     | After the mouse is moved in, the display delay time, in milliseconds (only effective when the trigger is hover/focus)                                                                                                                        | number                      | 50                  |            |
-| mouseLeaveDelay     | The time for the delay to disappear after the mouse is moved out, in milliseconds (only effective when the trigger is hover/focus), and is not less than mouseEnterDelay                                                                                                           | number                      | 50                  |            |
+| mouseLeaveDelay     | The time for the delay to disappear after the mouse is moved out, in milliseconds (only effective when the trigger is hover/focus), and is not less than mouseEnterDelay                                                                     | number                      | 50                  |            |
 | motion              | Whether to show the pop-up motion                                                                                                                                                                                                            | boolean                     | true               |            |
 | position            | Pop-up layer display position, optional value: `top`, `topLeft`, `topRight`, `left`, `leftTop`, `leftBottom`, `right`, `rightTop`, `rightBottom`, `bottom`, `bottomLeft`, `bottomRight`                                                      | string                      | 'top'               |            |
 | prefixCls           | The `className` prefix of the pop-up layer wrapper div. When this item is set, the pop-up layer will no longer have the style of Tooltip.                                                                                                    | string                      | 'semi-tooltip '     |            |
@@ -398,7 +398,7 @@ import { Popconfirm, Tooltip, Button } from '@douyinfe/semi-ui';
 | wrapperClassName | When children are disabled or children are multiple elements, the outer layer will wrap a layer of span elements, and the api is used to set the style class name of this span | string |  | 1.32.0 |
 | zIndex              | Bullet levels.                                                                                                                                                                                                                               | number                      | 1060                |            |
 | onVisibleChange     | A callback triggered when the pop-up layer is displayed/hidden                                                                                                                                                                               | (isVisble: boolean) => void |                     |            |
-
+| onClickOutSide      | Callback when the pop-up layer is in the display state and the non-Children, non-floating layer inner area is clicked (only valid when trigger is custom, click)                                                                             | (e:event) => void           |                     | **2.1.0** |
 ## Design Tokens
 <DesignToken/>
 

+ 1 - 1
content/show/tooltip/index.md

@@ -432,7 +432,7 @@ function Demo() {
 | wrapperClassName | 当 children 为 disabled ,或者 children 为多个元素时,外层将会包裹一层 span 元素,该 api 用于设置此 span 的样式类名 | string |  | **1.32.0** |
 | zIndex | 弹层层级 | number | 1060 |  |
 | onVisibleChange | 弹出层展示/隐藏时触发的回调 | function(isVisible:boolean) |  |  |
-
+| onClickOutSide | 当弹出层处于展示状态,点击非Children、非浮层内部区域时的回调(仅trigger为custom、click时有效)| function(e:event) |  | **2.1.0** |
 ## 设计变量
 
 <DesignToken/>

+ 5 - 0
packages/semi-foundation/popconfirm/popconfirmFoundation.ts

@@ -7,6 +7,7 @@ export interface PopconfirmAdapter<P = Record<string, any>, S = Record<string, a
     notifyConfirm: (e: any) => void;
     notifyCancel: (e: any) => void;
     notifyVisibleChange: (visible: boolean) => void;
+    notifyClickOutSide: (e: any) => void;
 }
 
 export default class PopConfirmFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<PopconfirmAdapter<P, S>, P, S> {
@@ -25,6 +26,10 @@ export default class PopConfirmFoundation<P = Record<string, any>, S = Record<st
         this.handleVisibleChange(false);
     }
 
+    handleClickOutSide(e: any): void {
+        this._adapter.notifyClickOutSide(e);
+    }
+
     handleVisibleChange(visible: boolean): void {
         if (!this._isControlledComponent('visible')) {
             this._adapter.setVisible(visible);

+ 4 - 2
packages/semi-foundation/tooltip/foundation.ts

@@ -92,8 +92,8 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
     }
 
     _bindEvent() {
-        const types = this.getProp('trigger'); // get trigger type
-        const { triggerEventSet, portalEventSet } = this._generateEvent(types);
+        const trigger = this.getProp('trigger'); // get trigger type
+        const { triggerEventSet, portalEventSet } = this._generateEvent(trigger);
         this._bindTriggerEvent(triggerEventSet);
         this._bindPortalEvent(portalEventSet);
         this._bindResizeEvent();
@@ -268,6 +268,8 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
         this._adapter.insertPortal(content, position);
 
         if (trigger === 'custom') {
+            // eslint-disable-next-line
+            this._adapter.registerClickOutsideHandler(() => {});
             this._togglePortalVisible(true);
         }
 

+ 29 - 0
packages/semi-ui/popconfirm/_story/popconfirm.stories.js

@@ -4,6 +4,7 @@ import Popconfirm from '../index';
 import Button from '../../button';
 import Input from '../../input';
 import Table from '../../table';
+import Toast from '../../toast';
 
 import TypesConfrimDemo from './TypesConfirm';
 import DynamicDisableDemo from './DynamicDisable';
@@ -139,3 +140,31 @@ export const ShowArrowDemo = () => <ShowArrow />;
 ShowArrowDemo.style = {
   name: 'show arrow'
 }
+
+export const ClickOutSideDemo = () => {
+    const [v, setV] = useState(false)
+    const onConfirm = () => {
+      Toast.success('确认保存!');
+    };
+
+    const onCancel = () => {
+      Toast.warning('取消保存!');
+    }
+    return (
+      <Popconfirm
+          title="确定是否要保存此修改?"
+          content="此修改将不可逆"
+          visible={v}
+          onClickOutSide={onCancel}
+          onConfirm={onConfirm}
+          onCancel={onCancel}
+      >
+          <Button onClick={() => setV(true)}>保存</Button>
+      </Popconfirm>
+    )
+}
+
+
+ClickOutSideDemo.story = {
+  name: 'ClickOutSideDemo',
+};

+ 8 - 1
packages/semi-ui/popconfirm/index.tsx

@@ -38,6 +38,7 @@ export interface PopconfirmProps extends PopoverProps {
     onCancel?: (e: React.MouseEvent) => void;
     onConfirm?: (e: React.MouseEvent) => void;
     onVisibleChange?: (visible: boolean) => void;
+    onClickOutSide?: (e: React.MouseEvent) => void;
 }
 
 export interface PopconfirmState {
@@ -65,13 +66,14 @@ export default class Popconfirm extends BaseComponent<PopconfirmProps, Popconfir
         cancelType: PropTypes.string,
         onCancel: PropTypes.func,
         onConfirm: PropTypes.func,
-        zIndex: PropTypes.number,
+        onClickOutSide: PropTypes.func,
         onVisibleChange: PropTypes.func,
         visible: PropTypes.bool,
         defaultVisible: PropTypes.bool,
         okButtonProps: PropTypes.object,
         cancelButtonProps: PropTypes.object,
         stopPropagation: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
+        zIndex: PropTypes.number,
         // private
         trigger: PropTypes.string,
         position: PropTypes.string,
@@ -90,6 +92,7 @@ export default class Popconfirm extends BaseComponent<PopconfirmProps, Popconfir
         zIndex: numbers.DEFAULT_Z_INDEX,
         onCancel: noop,
         onConfirm: noop,
+        onClickOutSide: noop,
     };
 
     constructor(props: PopconfirmProps) {
@@ -120,6 +123,7 @@ export default class Popconfirm extends BaseComponent<PopconfirmProps, Popconfir
             notifyConfirm: (e: React.MouseEvent): void => this.props.onConfirm(e),
             notifyCancel: (e: React.MouseEvent): void => this.props.onCancel(e),
             notifyVisibleChange: (visible: boolean): void => this.props.onVisibleChange(visible),
+            notifyClickOutSide: (e: React.MouseEvent) => this.props.onClickOutSide(e),
         };
     }
 
@@ -129,6 +133,8 @@ export default class Popconfirm extends BaseComponent<PopconfirmProps, Popconfir
 
     handleVisibleChange = (visible: boolean): void => this.foundation.handleVisibleChange(visible);
 
+    handleClickOutSide = (e: React.MouseEvent) => this.foundation.handleClickOutSide(e);
+
     stopImmediatePropagation = (e: React.SyntheticEvent): void => e && e.nativeEvent && e.nativeEvent.stopImmediatePropagation();
 
     renderControls() {
@@ -211,6 +217,7 @@ export default class Popconfirm extends BaseComponent<PopconfirmProps, Popconfir
         const popProps: PopProps = {
             onVisibleChange: this.handleVisibleChange,
             className: cssClasses.POPOVER,
+            onClickOutSide: this.handleClickOutSide,
         };
 
         if (this.isControlled('visible')) {

+ 4 - 7
packages/semi-ui/popover/index.tsx

@@ -8,6 +8,7 @@ import Arrow from './Arrow';
 import '@douyinfe/semi-foundation/popover/popover.scss';
 import { BaseProps } from '../_base/baseComponent';
 import { Motion } from '../_base/base';
+import { noop } from 'lodash-es';
 
 export { ArrowProps } from './Arrow';
 declare interface ArrowStyle {
@@ -28,6 +29,7 @@ export interface PopoverProps extends BaseProps {
     trigger?: Trigger;
     contentClassName?: string | any[];
     onVisibleChange?: (visible: boolean) => void;
+    onClickOutSide?: (e: React.MouseEvent) => void;
     showArrow?: boolean;
     spacing?: number;
     stopPropagation?: boolean | string;
@@ -61,6 +63,7 @@ class Popover extends React.PureComponent<PopoverProps, PopoverState> {
         trigger: PropTypes.oneOf(triggerSet).isRequired,
         contentClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
         onVisibleChange: PropTypes.func,
+        onClickOutSide: PropTypes.func,
         style: PropTypes.object,
         spacing: PropTypes.number,
         zIndex: PropTypes.number,
@@ -86,15 +89,9 @@ class Popover extends React.PureComponent<PopoverProps, PopoverState> {
         okText: 'Yes',
         position: 'bottom',
         prefixCls: cssClasses.PREFIX,
+        onClickOutSide: noop,
     };
 
-    constructor(props: PopoverProps) {
-        super(props);
-        this.state = {
-            popConfirmVisible: false,
-        };
-    }
-
     renderPopCard() {
         const { content, contentClassName, prefixCls } = this.props;
         const { direction } = this.context;

+ 23 - 0
packages/semi-ui/tooltip/_story/tooltip.stories.js

@@ -665,3 +665,26 @@ export const ShowArrow = () => {
 ShowArrow.story = {
   name: 'showArrow',
 };
+
+export const OnClickOutSideDemo = () => {
+    let [v, setV] = useState(false);
+    let clickOutSide = () => {
+        console.log('clickOutSide');
+        setV(false);
+    }
+    return (
+        <>
+            <Tooltip onClickOutSide={() => clickOutSide()} content={'hi bytedance'} visible={v} trigger='custom'>
+                <Button onClick={() => setV(true)}>按钮</Button>
+            </Tooltip>
+            <br />
+            <br />
+            <Tooltip onClickOutSide={() => console.log('clickOutSide')} content={'hi bytedance'} trigger='click'>
+                <Button >单个按钮</Button>
+            </Tooltip>
+        </>
+    );
+}
+OnClickOutSideDemo.story = {
+  name: 'OnClickOutSide',
+};

+ 4 - 0
packages/semi-ui/tooltip/index.tsx

@@ -51,6 +51,7 @@ export interface TooltipProps extends BaseProps {
     content?: React.ReactNode;
     prefixCls?: string;
     onVisibleChange?: (visible: boolean) => void;
+    onClickOutSide?: (e: React.MouseEvent) => void;
     spacing?: number;
     showArrow?: boolean | React.ReactNode;
     zIndex?: number;
@@ -106,6 +107,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
         content: PropTypes.node,
         prefixCls: PropTypes.string,
         onVisibleChange: PropTypes.func,
+        onClickOutSide: PropTypes.func,
         spacing: PropTypes.number,
         showArrow: PropTypes.oneOfType([PropTypes.bool, PropTypes.node]),
         zIndex: PropTypes.number,
@@ -131,6 +133,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
         mouseEnterDelay: numbers.MOUSE_ENTER_DELAY,
         mouseLeaveDelay: numbers.MOUSE_LEAVE_DELAY,
         onVisibleChange: noop,
+        onClickOutSide: noop,
         spacing: numbers.SPACING,
         showArrow: true,
         arrowBounding: numbers.ARROW_BOUNDING,
@@ -310,6 +313,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
                         (el && !(el as any).contains(e.target) && popupEl && !(popupEl as any).contains(e.target)) ||
                         this.props.clickTriggerToHide
                     ) {
+                        this.props.onClickOutSide(e);
                         cb();
                     }
                 };