mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
refactor(directives): [trap-focus] refactor (#8818)
This commit is contained in:
@@ -5,7 +5,7 @@ import { afterAll, afterEach, describe, expect, test, vi } from 'vitest'
|
||||
import * as Aria from '@element-plus/utils/dom/aria'
|
||||
|
||||
import TrapFocus, { FOCUSABLE_CHILDREN } from '../trap-focus'
|
||||
import type { ITrapFocusElement } from '../trap-focus'
|
||||
import type { TrapFocusElement } from '../trap-focus'
|
||||
|
||||
const isVisibleMock = vi.spyOn(Aria, 'isVisible').mockImplementation(() => true)
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('v-trap-focus', () => {
|
||||
</div>
|
||||
`)
|
||||
expect(
|
||||
(wrapper.element as ITrapFocusElement)[FOCUSABLE_CHILDREN].length
|
||||
(wrapper.element as TrapFocusElement)[FOCUSABLE_CHILDREN].length
|
||||
).toBe(1)
|
||||
})
|
||||
|
||||
@@ -63,7 +63,7 @@ describe('v-trap-focus', () => {
|
||||
</div>
|
||||
`)
|
||||
expect(
|
||||
(wrapper.element as ITrapFocusElement)[FOCUSABLE_CHILDREN].length
|
||||
(wrapper.element as TrapFocusElement)[FOCUSABLE_CHILDREN].length
|
||||
).toBe(5)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
// @ts-nocheck
|
||||
import { nextTick } from 'vue'
|
||||
import { obtainAllFocusableElements, off, on } from '@element-plus/utils'
|
||||
import { obtainAllFocusableElements } from '@element-plus/utils'
|
||||
import { EVENT_CODE } from '@element-plus/constants'
|
||||
import type { ObjectDirective } from 'vue'
|
||||
|
||||
export const FOCUSABLE_CHILDREN = '_trap-focus-children'
|
||||
export const TRAP_FOCUS_HANDLER = '_trap-focus-handler'
|
||||
|
||||
export interface ITrapFocusElement extends HTMLElement {
|
||||
export interface TrapFocusElement extends HTMLElement {
|
||||
[FOCUSABLE_CHILDREN]: HTMLElement[]
|
||||
[TRAP_FOCUS_HANDLER]: (e: KeyboardEvent) => void
|
||||
}
|
||||
|
||||
const FOCUS_STACK = []
|
||||
const FOCUS_STACK: TrapFocusElement[] = []
|
||||
|
||||
const FOCUS_HANDLER = (e: KeyboardEvent) => {
|
||||
// Getting the top layer.
|
||||
@@ -42,7 +41,7 @@ const FOCUS_HANDLER = (e: KeyboardEvent) => {
|
||||
// the is critical since jsdom did not implement user actions, you can only mock it
|
||||
// DELETE ME: when testing env switches to puppeteer
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
const index = focusableElement.indexOf(e.target)
|
||||
const index = focusableElement.indexOf(e.target as HTMLElement)
|
||||
if (index !== -1) {
|
||||
focusableElement[goingBackward ? index - 1 : index + 1]?.focus()
|
||||
}
|
||||
@@ -51,14 +50,14 @@ const FOCUS_HANDLER = (e: KeyboardEvent) => {
|
||||
}
|
||||
|
||||
const TrapFocus: ObjectDirective = {
|
||||
beforeMount(el: ITrapFocusElement) {
|
||||
beforeMount(el: TrapFocusElement) {
|
||||
el[FOCUSABLE_CHILDREN] = obtainAllFocusableElements(el)
|
||||
FOCUS_STACK.push(el)
|
||||
if (FOCUS_STACK.length <= 1) {
|
||||
on(document, 'keydown', FOCUS_HANDLER)
|
||||
document.addEventListener('keydown', FOCUS_HANDLER)
|
||||
}
|
||||
},
|
||||
updated(el: ITrapFocusElement) {
|
||||
updated(el: TrapFocusElement) {
|
||||
nextTick(() => {
|
||||
el[FOCUSABLE_CHILDREN] = obtainAllFocusableElements(el)
|
||||
})
|
||||
@@ -66,7 +65,7 @@ const TrapFocus: ObjectDirective = {
|
||||
unmounted() {
|
||||
FOCUS_STACK.shift()
|
||||
if (FOCUS_STACK.length === 0) {
|
||||
off(document, 'keydown', FOCUS_HANDLER)
|
||||
document.removeEventListener('keydown', FOCUS_HANDLER)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user