feat: modal add closeIcon support

pull/1845/head
tangjinzhou 2020-02-22 13:22:24 +08:00
parent 078a3e4fff
commit e43f6905be
12 changed files with 113 additions and 90 deletions

View File

@ -1,5 +1,5 @@
module.exports = {
dev: {
componentName: 'message', // dev components
componentName: 'modal', // dev components
},
};

View File

@ -48,7 +48,10 @@ export default {
// this.setState({ loading: false });
closeModal(...args);
},
() => {
e => {
// Emit error when catch promise reject
// eslint-disable-next-line no-console
console.error(e);
// See: https://github.com/ant-design/ant-design/issues/6183
this.setState({ loading: false });
},

View File

@ -27,6 +27,7 @@ export default {
} = props;
warning(
!('iconType' in props),
'Modal',
`The property 'iconType' is deprecated. Use the property 'icon' instead.`,
);
const icon = props.icon ? props.icon : iconType;
@ -92,9 +93,9 @@ export default {
<div class={`${contentPrefixCls}-body-wrapper`}>
<div class={`${contentPrefixCls}-body`}>
{iconNode}
<span class={`${contentPrefixCls}-title`}>
{typeof props.title === 'function' ? props.title(h) : props.title}
</span>
{props.title === undefined ? null : (
<span class={`${contentPrefixCls}-title`}>{props.title}</span>
)}
<div class={`${contentPrefixCls}-content`}>
{typeof props.content === 'function' ? props.content(h) : props.content}
</div>

View File

@ -19,7 +19,23 @@ import {
import { ConfigConsumerProps } from '../config-provider';
let mousePosition = null;
let mousePositionEventBinded = false;
// ref: https://github.com/ant-design/ant-design/issues/15795
const getClickPosition = e => {
mousePosition = {
x: e.pageX,
y: e.pageY,
};
// 100ms
// zoom
//
setTimeout(() => (mousePosition = null), 100);
};
//
if (typeof window !== 'undefined' && window.document && window.document.documentElement) {
addEventListener(document.documentElement, 'click', getClickPosition);
}
function noop() {}
const modalProps = (defaultProps = {}) => {
const props = {
@ -32,6 +48,7 @@ const modalProps = (defaultProps = {}) => {
title: PropTypes.any,
/** 是否显示右上角的关闭按钮*/
closable: PropTypes.bool,
closeIcon: PropTypes.any,
/** 点击确定回调*/
// onOk: (e: React.MouseEvent<any>) => void,
/** 点击模态框右上角叉、取消按钮、Props.maskClosable 值为 true 时的遮罩层或键盘按下 Esc 时的回调*/
@ -88,31 +105,23 @@ export default {
confirmLoading: false,
visible: false,
okType: 'primary',
// okButtonDisabled: false,
// cancelButtonDisabled: false,
}),
data() {
return {
sVisible: !!this.visible,
};
},
watch: {
visible(val) {
// getClickPosition render render
setTimeout(() => {
this.sVisible = val;
});
},
},
inject: {
configProvider: { default: () => ConfigConsumerProps },
},
mounted() {
if (mousePositionEventBinded) {
return;
}
//
addEventListener(document.documentElement, 'click', e => {
mousePosition = {
x: e.pageX,
y: e.pageY,
};
// 100ms
// zoom
//
setTimeout(() => {
mousePosition = null;
}, 100);
});
mousePositionEventBinded = true;
},
// static info: ModalFunc;
// static success: ModalFunc;
// static error: ModalFunc;
@ -158,14 +167,16 @@ export default {
render() {
const {
prefixCls: customizePrefixCls,
visible,
sVisible: visible,
wrapClassName,
centered,
getContainer,
$slots,
$scopedSlots,
$attrs,
} = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const children = $scopedSlots.default ? $scopedSlots.default() : $slots.default;
const { getPrefixCls, getPopupContainer: getContextPopupContainer } = this.configProvider;
const prefixCls = getPrefixCls('modal', customizePrefixCls);
const defaultFooter = (
@ -175,9 +186,10 @@ export default {
scopedSlots={{ default: this.renderFooter }}
/>
);
const closeIcon = (
const closeIcon = getComponentFromProp(this, 'closeIcon');
const closeIconToRender = (
<span class={`${prefixCls}-close-x`}>
<Icon class={`${prefixCls}-close-icon`} type={'close'} />
{closeIcon || <Icon class={`${prefixCls}-close-icon`} type={'close'} />}
</span>
);
const footer = getComponentFromProp(this, 'footer');
@ -185,13 +197,14 @@ export default {
const dialogProps = {
props: {
...this.$props,
getContainer: getContainer === undefined ? getContextPopupContainer : getContainer,
prefixCls,
wrapClassName: classNames({ [`${prefixCls}-centered`]: !!centered }, wrapClassName),
title,
footer: footer === undefined ? defaultFooter : footer,
visible: visible,
mousePosition,
closeIcon,
closeIcon: closeIconToRender,
},
on: {
...getListeners(this),
@ -201,6 +214,6 @@ export default {
style: getStyle(this),
attrs: $attrs,
};
return <Dialog {...dialogProps}>{$slots.default}</Dialog>;
return <Dialog {...dialogProps}>{children}</Dialog>;
},
};

View File

@ -1,6 +1,7 @@
import { mount } from '@vue/test-utils';
import Vue from 'vue';
import Modal from '..';
import mountTest from '../../../tests/shared/mountTest';
const ModalTester = {
props: ['footer', 'visible'],
@ -26,6 +27,7 @@ const ModalTester = {
};
describe('Modal', () => {
mountTest(Modal);
it('render correctly', done => {
const wrapper = mount({
render() {
@ -38,10 +40,10 @@ describe('Modal', () => {
sync: false,
});
wrapper1.setProps({ visible: true });
Vue.nextTick(() => {
setTimeout(() => {
expect(wrapper1.html()).toMatchSnapshot();
done();
});
}, 10);
});
it('render without footer', () => {

View File

@ -5,7 +5,7 @@
<us>
#### Confirmation modal dialog
To use `confirm()` to popup a confirmation modal dialog.
To use `confirm()` to show a confirmation modal dialog.
</us>
```tpl

View File

@ -5,7 +5,7 @@
<us>
#### Manual to update destroy
Manually updateing and destroying a modal from `Modal.method`.
Manually updating and destroying a modal from `Modal.method`.
</us>
```tpl

View File

@ -1,29 +1,30 @@
## API
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| afterClose | Specify a function that will be called when modal is closed completely. | function | - |
| bodyStyle | Body style for modal body element. Such as height, padding etc. | object | {} |
| cancelText | Text of the Cancel button | string\|slot | `Cancel` |
| centered | Centered Modal | Boolean | `false` |
| closable | Whether a close (x) button is visible on top right of the modal dialog or not | boolean | true |
| confirmLoading | Whether to apply loading visual effect for OK button or not | boolean | false |
| destroyOnClose | Whether to unmount child components on onClose | boolean | false |
| footer | Footer content, set as `:footer="null"` when you don't need default buttons | string\|slot | OK and Cancel buttons |
| forceRender | Force render Modal | boolean | false |
| getContainer | Return the mount node for Modal | (instance): HTMLElement | () => document.body |
| mask | Whether show mask or not. | Boolean | true |
| maskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | boolean | true |
| maskStyle | Style for modal's mask element. | object | {} |
| okText | Text of the OK button | string\|slot | `OK` |
| okType | Button `type` of the OK button | string | `primary` |
| okButtonProps | The ok button props, follow jsx [rules](https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx) | {props: [ButtonProps](/components/button/#API), on: {}} | - |
| cancelButtonProps | The cancel button props, follow jsx [rules](https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx) | {props: [ButtonProps](/components/button/#API), on: {}} | - |
| title | The modal dialog's title | string\|slot | - |
| visible | Whether the modal dialog is visible or not | boolean | false |
| width | Width of the modal dialog | string\|number | 520 |
| wrapClassName | The class name of the container of the modal dialog | string | - |
| zIndex | The `z-index` of the Modal | Number | 1000 |
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| afterClose | Specify a function that will be called when modal is closed completely. | function | - | |
| bodyStyle | Body style for modal body element. Such as height, padding etc. | object | {} | |
| cancelText | Text of the Cancel button | string\|slot | `Cancel` | |
| centered | Centered Modal | Boolean | `false` | |
| closable | Whether a close (x) button is visible on top right of the modal dialog or not | boolean | true | |
| closeIcon | custom close icon | VNode \| slot | - | 1.5.0 |
| confirmLoading | Whether to apply loading visual effect for OK button or not | boolean | false | |
| destroyOnClose | Whether to unmount child components on onClose | boolean | false | |
| footer | Footer content, set as `:footer="null"` when you don't need default buttons | string\|slot | OK and Cancel buttons | |
| forceRender | Force render Modal | boolean | false | |
| getContainer | Return the mount node for Modal | (instance): HTMLElement | () => document.body | |
| mask | Whether show mask or not. | Boolean | true | |
| maskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | boolean | true | |
| maskStyle | Style for modal's mask element. | object | {} | |
| okText | Text of the OK button | string\|slot | `OK` | |
| okType | Button `type` of the OK button | string | `primary` | |
| okButtonProps | The ok button props, follow jsx [rules](https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx) | {props: [ButtonProps](/components/button/#API), on: {}} | - | |
| cancelButtonProps | The cancel button props, follow jsx [rules](https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx) | {props: [ButtonProps](/components/button/#API), on: {}} | - | |
| title | The modal dialog's title | string\|slot | - | |
| visible | Whether the modal dialog is visible or not | boolean | false | |
| width | Width of the modal dialog | string\|number | 520 | |
| wrapClassName | The class name of the container of the modal dialog | string | - | |
| zIndex | The `z-index` of the Modal | Number | 1000 | |
### events

View File

@ -55,7 +55,7 @@ const warning = function(props) {
};
const warn = warning;
const confirm = function(props) {
const confirm = function confirmFn(props) {
const config = {
type: 'confirm',
okCancel: true,
@ -70,7 +70,7 @@ Modal.warning = warning;
Modal.warn = warn;
Modal.confirm = confirm;
Modal.destroyAll = function() {
Modal.destroyAll = function destroyAllFn() {
while (destroyFns.length) {
const close = destroyFns.pop();
if (close) {

View File

@ -1,30 +1,31 @@
## API
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| afterClose | Modal 完全关闭后的回调 | function | 无 |
| bodyStyle | Modal body 样式 | object | {} |
| cancelText | 取消按钮文字 | string\| slot | 取消 |
| centered | 垂直居中展示 Modal | Boolean | `false` |
| closable | 是否显示右上角的关闭按钮 | boolean | true |
| confirmLoading | 确定按钮 loading | boolean | 无 |
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false |
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `:footer="null"` | string\|slot | 确定取消按钮 |
| forceRender | 强制渲染 Modal | boolean | false |
| getContainer | 指定 Modal 挂载的 HTML 节点 | (instance): HTMLElement | () => document.body |
| keyboard | 是否支持键盘 esc 关闭 | boolean | true |
| mask | 是否展示遮罩 | Boolean | true |
| maskClosable | 点击蒙层是否允许关闭 | boolean | true |
| maskStyle | 遮罩样式 | object | {} |
| okText | 确认按钮文字 | string\|slot | 确定 |
| okType | 确认按钮类型 | string | primary |
| okButtonProps | ok 按钮 props, 遵循 jsx[规范](https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx) | {props: [ButtonProps](/components/button/#API), on: {}} | - |
| cancelButtonProps | cancel 按钮 props, 遵循 jsx[规范](https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx) | {props: [ButtonProps](/components/button/#API), on: {}} | - |
| title | 标题 | string\|slot | 无 |
| visible(v-model) | 对话框是否可见 | boolean | 无 |
| width | 宽度 | string\|number | 520 |
| wrapClassName | 对话框外层容器的类名 | string | - |
| zIndex | 设置 Modal 的 `z-index` | Number | 1000 |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| afterClose | Modal 完全关闭后的回调 | function | 无 | |
| bodyStyle | Modal body 样式 | object | {} | |
| cancelText | 取消按钮文字 | string\| slot | 取消 | |
| centered | 垂直居中展示 Modal | Boolean | `false` | |
| closable | 是否显示右上角的关闭按钮 | boolean | true | |
| closeIcon | 自定义关闭图标 | VNode \| slot | - | 1.5.0 |
| confirmLoading | 确定按钮 loading | boolean | 无 | |
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false | |
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `:footer="null"` | string\|slot | 确定取消按钮 | |
| forceRender | 强制渲染 Modal | boolean | false | |
| getContainer | 指定 Modal 挂载的 HTML 节点 | (instance): HTMLElement | () => document.body | |
| keyboard | 是否支持键盘 esc 关闭 | boolean | true | |
| mask | 是否展示遮罩 | Boolean | true | |
| maskClosable | 点击蒙层是否允许关闭 | boolean | true | |
| maskStyle | 遮罩样式 | object | {} | |
| okText | 确认按钮文字 | string\|slot | 确定 | |
| okType | 确认按钮类型 | string | primary | |
| okButtonProps | ok 按钮 props, 遵循 jsx[规范](https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx) | {props: [ButtonProps](/components/button/#API), on: {}} | - | |
| cancelButtonProps | cancel 按钮 props, 遵循 jsx[规范](https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx) | {props: [ButtonProps](/components/button/#API), on: {}} | - | |
| title | 标题 | string\|slot | 无 | |
| visible(v-model) | 对话框是否可见 | boolean | 无 | |
| width | 宽度 | string\|number | 520 | |
| wrapClassName | 对话框外层容器的类名 | string | - | |
| zIndex | 设置 Modal 的 `z-index` | Number | 1000 | |
### 事件

View File

@ -1,4 +1,4 @@
import defaultLocale from '../locale-provider/default';
import defaultLocale from '../locale/default';
// export interface ModalLocale {
// okText: string;

2
types/modal.d.ts vendored
View File

@ -179,6 +179,8 @@ export declare class Modal extends AntdComponent {
*/
closable: boolean;
closeIcon: any;
/**
* Whether to apply loading visual effect for OK button or not
* @default false