Skip to content

Commit e207024

Browse files
authored
feat(vue-renderless/drawer): add close-on-press-escape api (#3900)
1 parent dba9bfb commit e207024

File tree

8 files changed

+155
-4
lines changed

8 files changed

+155
-4
lines changed

examples/sites/demos/apis/drawer.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,20 @@ export default {
207207
mode: ['pc'],
208208
pcDemo: 'tips-props',
209209
hideSaas: true
210+
},
211+
{
212+
name: 'close-on-press-escape',
213+
type: 'boolean',
214+
defaultValue: 'false',
215+
desc: {
216+
'zh-CN': 'ESC 键关闭抽屉',
217+
'en-US': 'ESC key to close drawer'
218+
},
219+
mode: ['pc'],
220+
pcDemo: 'closeOnPressEscape',
221+
meta: {
222+
stable: '3.28.0'
223+
}
210224
}
211225
],
212226
events: [
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<template>
2+
<div>
3+
<tiny-button @click="openDrawer" type="primary"> 抽屉组件 </tiny-button>
4+
<tiny-drawer
5+
title="标题"
6+
:visible="visible"
7+
@update:visible="visible = $event"
8+
@confirm="confirm"
9+
:close-on-press-escape="true"
10+
>
11+
<div>内容区域</div>
12+
</tiny-drawer>
13+
</div>
14+
</template>
15+
16+
<script setup>
17+
import { ref } from 'vue'
18+
import { TinyDrawer, TinyButton } from '@opentiny/vue'
19+
20+
const visible = ref(false)
21+
22+
function openDrawer() {
23+
visible.value = true
24+
}
25+
26+
function confirm() {
27+
visible.value = false
28+
}
29+
</script>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { test, expect } from '@playwright/test'
2+
3+
test('按 Esc 键关闭 Drawer(close-on-press-escape)', async ({ page }) => {
4+
page.on('pageerror', (exception) => expect(exception).toBeNull())
5+
6+
await page.goto('drawer#close-on-press-escape')
7+
8+
const drawer = page.locator('.tiny-drawer__main')
9+
10+
// 打开 Drawer(用文本更稳定)
11+
await page.getByText('抽屉组件').click()
12+
await expect(drawer).toBeVisible()
13+
14+
// 按 Esc
15+
await page.keyboard.press('Escape')
16+
17+
// Drawer 关闭
18+
await expect(drawer).toBeHidden()
19+
})
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<template>
2+
<div>
3+
<tiny-button @click="openDrawer" type="primary"> 抽屉组件 </tiny-button>
4+
<tiny-drawer
5+
title="标题"
6+
:visible="visible"
7+
@update:visible="visible = $event"
8+
@confirm="confirm"
9+
:close-on-press-escape="true"
10+
>
11+
<div>内容区域</div>
12+
</tiny-drawer>
13+
</div>
14+
</template>
15+
16+
<script>
17+
import { TinyDrawer, TinyButton } from '@opentiny/vue'
18+
19+
export default {
20+
components: {
21+
TinyDrawer,
22+
TinyButton
23+
},
24+
data() {
25+
return {
26+
visible: false
27+
}
28+
},
29+
methods: {
30+
openDrawer() {
31+
this.visible = true
32+
},
33+
confirm() {
34+
this.visible = false
35+
}
36+
}
37+
}
38+
</script>

examples/sites/demos/pc/app/drawer/webdoc/drawer.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ export default {
1616
},
1717
codeFiles: ['basic-usage.vue']
1818
},
19+
{
20+
demoId: 'close-on-press-escape',
21+
name: {
22+
'zh-CN': '按下 ESC 关闭抽屉',
23+
'en-US': ''
24+
},
25+
desc: {
26+
'zh-CN': '<p>添加 <code>close-on-press-escape</code> 属性可以控制是否可以通过 ESC 关闭抽屉。</p>',
27+
'en-US': ''
28+
},
29+
codeFiles: ['close-on-press-escape.vue']
30+
},
1931
{
2032
demoId: 'use-through-method',
2133
name: { 'zh-CN': '通过方法调用', 'en-US': 'Use through method' },

packages/renderless/src/drawer/index.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,36 @@ export const handleClose =
8080
}
8181
}
8282

83+
/* ================= Esc 关闭(受控) ================= */
84+
export const keydown =
85+
({ api, state, props }: Pick<IDrawerRenderlessParams, 'api' | 'state' | 'props'>) =>
86+
(event: KeyboardEvent) => {
87+
if (!state.visible) {
88+
return
89+
}
90+
91+
if (!props.closeOnPressEscape) {
92+
return
93+
}
94+
95+
if (event.key === 'Escape' || event.key === 'Esc') {
96+
api.handleClose('esc', true)
97+
}
98+
}
99+
100+
export const addKeydownEvent =
101+
({ api }: { api: IDrawerApi }) =>
102+
() => {
103+
document.addEventListener('keydown', api.keydown)
104+
}
105+
106+
export const removeKeydownEvent =
107+
({ api }: { api: IDrawerApi }) =>
108+
() => {
109+
document.removeEventListener('keydown', api.keydown)
110+
}
111+
/* ================================================== */
112+
83113
export const mousedown =
84114
({ state, vm }: { vm: ISharedRenderlessParamUtils<IDrawerCT>['vm']; state: IDrawerState }) =>
85115
(event) => {

packages/renderless/src/drawer/vue.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import {
1212
handleClose,
1313
computedWidth,
1414
computedHeight,
15-
open
15+
open,
16+
keydown,
17+
addKeydownEvent,
18+
removeKeydownEvent
1619
} from './index'
1720
import type {
1821
IDrawerProps,
@@ -50,8 +53,11 @@ export const renderless = (
5053
mousedown: mousedown({ state, vm }),
5154
mousemove: mousemove({ state, props, emit }),
5255
mouseup: mouseup({ state }),
53-
addDragEvent: addDragEvent({ api: api as IDrawerApi, vm }),
54-
removeDragEvent: removeDragEvent({ api: api as IDrawerApi, vm }),
56+
keydown: keydown({ api, state, props }),
57+
addKeydownEvent: addKeydownEvent({ api }),
58+
removeKeydownEvent: removeKeydownEvent({ api }),
59+
addDragEvent: addDragEvent({ api, vm }),
60+
removeDragEvent: removeDragEvent({ api, vm }),
5561
watchVisible: watchVisible({ state, api }),
5662
showScrollbar: showScrollbar(lockScrollClass),
5763
hideScrollbar: hideScrollbar(lockScrollClass),
@@ -61,13 +67,15 @@ export const renderless = (
6167

6268
onMounted(() => {
6369
props.dragable && api.addDragEvent()
70+
api.addKeydownEvent()
6471
if (props.lockScroll && props.visible) {
6572
api.showScrollbar()
6673
}
6774
})
6875

6976
onBeforeUnmount(() => {
7077
props.dragable && api.removeDragEvent()
78+
api.removeKeydownEvent()
7179
props.lockScroll && api.hideScrollbar()
7280
})
7381

packages/vue/src/drawer/src/pc.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ export default defineComponent({
161161
'zIndex',
162162
'beforeClose',
163163
'tipsProps',
164-
'customSlots'
164+
'customSlots',
165+
'closeOnPressEscape'
165166
],
166167
emits: ['update:visible', 'open', 'close', 'confirm', 'drag'],
167168
setup(props, context) {

0 commit comments

Comments
 (0)