feat: modal add closeIcon support
parent
078a3e4fff
commit
e43f6905be
|
@ -1,5 +1,5 @@
|
|||
module.exports = {
|
||||
dev: {
|
||||
componentName: 'message', // dev components
|
||||
componentName: 'modal', // dev components
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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 });
|
||||
},
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 | |
|
||||
|
||||
### 事件
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import defaultLocale from '../locale-provider/default';
|
||||
import defaultLocale from '../locale/default';
|
||||
|
||||
// export interface ModalLocale {
|
||||
// okText: string;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue