feat(dialog): useDialog add onMaskClick (#561)

Co-authored-by: 07akioni <07akioni2@gmail.com>
This commit is contained in:
Yugang Cao 2021-07-23 01:46:30 +08:00 committed by GitHub
parent 3c687c7d8e
commit a4fbbacd69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 164 additions and 3 deletions

View File

@ -8,6 +8,7 @@
- `n-dropdown` add `render-icon` prop.
- `n-checkbox-group` add `min` and `max` prop.
- `n-mention` add `empty` slot.
- `useDialog` option add `on-mask-click` prop, closes [#419](https://github.com/TuSimple/naive-ui/issues/419).
- `n-space` `justify` prop supports `center`, `space-around` and `space-between`.
### Fixes

View File

@ -8,6 +8,7 @@
- `n-dropdown` 新增 `render-icon` 属性
- `n-checkbox-group` 新增 `min``max` 属性
- `n-mention` 新增 `empty` slot
- `useDialog` 选项 新增 `on-mask-click`属性, 关闭 [#419](https://github.com/TuSimple/naive-ui/issues/419)
- `n-space` `justify` 属性支持 `center`、`space-around` 和 `space-between`
### Fixes

View File

@ -36,6 +36,7 @@ export default {
basic
async
use-component
mask
```
## API
@ -70,6 +71,7 @@ use-component
| onClose | `() => boolean \| Promise<boolean> \| any` | `undefined` | The default behavior is closing the confirm. Return `false` or resolve `false` or Promise rejected will prevent the default behavior. |
| onNegativeClick | `() => boolean \| Promise<boolean> \| any` | `undefined` | The default behavior is closing the confirm. Return `false` or resolve `false` or Promise rejected will prevent the default behavior. |
| onPositiveClick | `() => boolean \| Promise<boolean> \| any` | `undefined` | The default behavior is closing the confirm. Return `false` or resolve `false` or Promise rejected will prevent the default behavior. |
| onMaskClick | `() => void` | `undefined` | Callback triggered when click the mask. |
### DialogReactive API

View File

@ -0,0 +1,46 @@
# Mask
Dialog mask.
```html
<n-space>
<n-button @click="handleMask">mask</n-button>
<n-button @click="handleClose">cannot close</n-button>
</n-space>
```
```js
import { useMessage, useDialog } from 'naive-ui'
export default {
setup () {
const message = useMessage()
const dialog = useDialog()
return {
handleMask () {
dialog.success({
title: 'Close',
content: 'Are you sure?',
positiveText: 'Sure',
negativeText: 'Not Sure',
onMaskClick: (e) => {
message.success('click mask')
}
})
},
handleClose () {
dialog.success({
title: 'Close',
content: 'Are you sure?',
positiveText: 'Sure',
negativeText: 'Not Sure',
maskClosable: false,
onMaskClick: (e) => {
message.success('cannot close')
}
})
}
}
}
}
```

View File

@ -37,6 +37,7 @@ export default {
basic
async
use-component
mask
```
## API
@ -71,6 +72,7 @@ use-component
| onClose | `() => boolean \| Promise<boolean> \| any` | `undefined` | 默认行为是关闭确认框。返回 `false` 或者 resolve `false` 或者 Promise 被 reject 会避免默认行为 |
| onNegativeClick | `() => boolean \| Promise<boolean> \| any` | `undefined` | 默认行为是关闭确认框。返回 `false` 或者 resolve `false` 或者 Promise 被 reject 会避免默认行为 |
| onPositiveClick | `() => boolean \| Promise<boolean> \| any` | `undefined` | 默认行为是关闭确认框。返回 `false` 或者 resolve `false` 或者 Promise 被 reject 会避免默认行为 |
| onMaskClick | `() => void` | `undefined` | 点击蒙层后执行的回调 |
### DialogReactive API

View File

@ -0,0 +1,46 @@
# 蒙层
对话框有蒙层
```html
<n-space>
<n-button @click="handleMask">蒙层</n-button>
<n-button @click="handleClose">不可关闭</n-button>
</n-space>
```
```js
import { useMessage, useDialog } from 'naive-ui'
export default {
setup () {
const message = useMessage()
const dialog = useDialog()
return {
handleMask () {
dialog.success({
title: '关闭',
content: '你确定?',
positiveText: '确定',
negativeText: '不确定',
onMaskClick: (e) => {
message.success('点击蒙层')
}
})
},
handleClose () {
dialog.success({
title: '关闭',
content: '你确定?',
positiveText: '确定',
negativeText: '不确定',
maskClosable: false,
onMaskClick: (e) => {
message.success('不能关闭')
}
})
}
}
}
}
```

View File

@ -17,7 +17,8 @@ export const exposedDialogEnvProps = {
onNegativeClick: Function as PropType<
(e: MouseEvent) => Promise<boolean> | boolean | unknown
>,
onClose: Function as PropType<() => Promise<boolean> | boolean | unknown>
onClose: Function as PropType<() => Promise<boolean> | boolean | unknown>,
onMaskClick: Function as PropType<(e: MouseEvent) => void>
}
export default defineComponent({
@ -73,6 +74,13 @@ export default defineComponent({
hide()
}
}
function handleMaskClick (e: MouseEvent): void {
const { onMaskClick, maskClosable } = props
if (onMaskClick) {
onMaskClick(e)
maskClosable && hide()
}
}
function hide (): void {
showRef.value = false
}
@ -86,7 +94,8 @@ export default defineComponent({
handleAfterLeave,
handleCloseClick,
handleNegativeClick,
handlePositiveClick
handlePositiveClick,
handleMaskClick
}
},
render () {
@ -96,6 +105,7 @@ export default defineComponent({
handleNegativeClick,
handleCloseClick,
handleAfterLeave,
handleMaskClick,
to,
maskClosable,
show
@ -104,6 +114,7 @@ export default defineComponent({
<NModal
show={show}
onUpdateShow={handleUpdateShow}
onMaskClick={handleMaskClick}
appear
dialog
to={to}

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import { defineComponent, h } from 'vue'
import { defineComponent, h, nextTick } from 'vue'
import { NDialogProvider, useDialog, NDialog } from '../index'
const Provider = defineComponent({
@ -69,4 +69,51 @@ describe('n-dialog', () => {
await mount(() => <Provider>{{ default: () => <Test /> }}</Provider>)
expect(document.querySelector('.n-button__icon')).not.toEqual(null)
})
it('maskClosable', async () => {
const mousedownEvent = new MouseEvent('mousedown', { bubbles: true })
const mouseupEvent = new MouseEvent('mouseup', { bubbles: true })
const Test = defineComponent({
setup () {
const dialog = useDialog()
dialog.success({
title: 'Close by mask',
content: 'Content',
maskClosable: false
})
},
render () {
return null
}
})
mount(() => <Provider>{{ default: () => <Test /> }}</Provider>)
document.body.dispatchEvent(mousedownEvent)
document.body.dispatchEvent(mouseupEvent)
await nextTick(() => {
expect(document.querySelector('.n-dialog')).not.toBeNull()
})
})
it('onMaskClick', async () => {
const onMaskClick = jest.fn()
const mousedownEvent = new MouseEvent('mousedown', { bubbles: true })
const mouseupEvent = new MouseEvent('mouseup', { bubbles: true })
const Test = defineComponent({
setup () {
const dialog = useDialog()
dialog.success({
title: 'Close by mask',
content: 'Content',
onMaskClick
})
},
render () {
return null
}
})
await mount(() => <Provider>{{ default: () => <Test /> }}</Provider>)
document.body.dispatchEvent(mousedownEvent)
document.body.dispatchEvent(mouseupEvent)
expect(onMaskClick).toHaveBeenCalled()
})
})

View File

@ -66,6 +66,7 @@ const modalProps = {
onClose: Function as PropType<() => Promise<boolean> | boolean | any>,
onPositiveClick: Function as PropType<() => Promise<boolean> | boolean | any>,
onNegativeClick: Function as PropType<() => Promise<boolean> | boolean | any>,
onMaskClick: Function as PropType<(e: MouseEvent) => void>,
// deprecated
overlayStyle: {
type: [String, Object] as PropType<string | CSSProperties | undefined>,
@ -192,6 +193,10 @@ export default defineComponent({
if (onAfterHide) onAfterHide()
}
function handleClickoutside (e: MouseEvent): void {
const { onMaskClick } = props
if (onMaskClick) {
onMaskClick(e)
}
if (props.maskClosable) {
if (containerRef.value?.contains(e.target as Node)) {
doUpdateShow(false)