Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions packages/components/dialog/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { forwardRef, useEffect, useRef, useImperativeHandle, useState } from 'react';
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import classNames from 'classnames';
import { isUndefined } from 'lodash-es';

import log from '@tdesign/common-js/log/index';
import { pxCompat } from '@tdesign/common-js/utils/helper';
import { canUseDocument } from '../_util/dom';
import Portal from '../common/Portal';
import useAttach from '../hooks/useAttach';
import useConfig from '../hooks/useConfig';
Expand All @@ -13,10 +15,10 @@ import useSetState from '../hooks/useSetState';
import { useLocaleReceiver } from '../locale/LocalReceiver';
import { dialogDefaultProps } from './defaultProps';
import DialogCard from './DialogCard';
import useDialogDrag from './hooks/useDialogDrag';
import useDialogEsc from './hooks/useDialogEsc';
import useLockStyle from './hooks/useLockStyle';
import useDialogDrag from './hooks/useDialogDrag';
import { canUseDocument } from '../_util/dom';

import type { StyledProps } from '../common';
import type { DialogInstance, TdDialogProps } from './type';

Expand Down Expand Up @@ -98,8 +100,8 @@ const Dialog = forwardRef<DialogInstance, DialogProps>((originalProps, ref) => {
const [animationVisible, setAnimationVisible] = useState(visible);
const [dialogAnimationVisible, setDialogAnimationVisible] = useState(false);

const { focusTopDialog } = useDialogEsc(visible, wrapRef);
useLockStyle({ preventScrollThrough, visible, mode, showInAttachedElement });
useDialogEsc(visible, wrapRef);
useDialogDrag({
dialogCardRef,
canDraggable: draggable && mode === 'modeless',
Expand Down Expand Up @@ -195,6 +197,7 @@ const Dialog = forwardRef<DialogInstance, DialogProps>((originalProps, ref) => {
const onAnimateLeave = () => {
onClosed?.();
setAnimationVisible(false);
focusTopDialog();
if (!wrapRef.current) return;
wrapRef.current.style.display = 'none';
};
Expand Down
53 changes: 35 additions & 18 deletions packages/components/dialog/hooks/useDialogEsc.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
import { useEffect, MutableRefObject } from 'react';
import { MutableRefObject, useCallback, useEffect, useRef } from 'react';

const dialogSet: Set<MutableRefObject<HTMLDivElement>> = new Set();
const dialogStack: MutableRefObject<HTMLDivElement>[] = [];

const useDialogEsc = (visible: boolean, dialog: MutableRefObject<HTMLDivElement>) => {
const addedToStackRef = useRef<boolean>(false);

// 关闭动画完成后调用,聚焦顶层 dialog
const focusTopDialog = useCallback(() => {
const lastDialog = dialogStack[dialogStack.length - 1];
if (lastDialog?.current) {
lastDialog.current.focus();
}
}, []);

// 每次渲染都执行,确保捕捉到的 current 不为 null
useEffect(() => {
if (visible) {
// 将 dialog 添加至 Set 对象
if (dialog?.current) {
dialogSet.add(dialog);
dialog?.current?.focus();
if (visible && dialog?.current && !addedToStackRef.current) {
dialogStack.push(dialog);
addedToStackRef.current = true;
dialog.current.focus();
}
});

// 处理 visible 变化
useEffect(() => {
if (!visible && addedToStackRef.current) {
const index = dialogStack.indexOf(dialog);
if (index > -1) {
dialogStack.splice(index, 1);
}
} else if (dialogSet.has(dialog)) {
// 将 dialog 从 Set 对象删除
dialogSet.delete(dialog);
const dialogList = [...dialogSet];
// 将 Set 对象中最后一个 dialog 设置为 focus
dialogList[dialogList.length - 1]?.current?.focus();
addedToStackRef.current = false;
}

return () => {
// 从 Set 对象删除无效的 dialog
dialogSet.forEach((item) => {
if (item.current === null) {
dialogSet.delete(item);
// 清理无效的 dialog
for (let i = dialogStack.length - 1; i >= 0; i--) {
if (dialogStack[i].current === null) {
dialogStack.splice(i, 1);
}
});
}
};
}, [visible, dialog]);

return { focusTopDialog };
};

export default useDialogEsc;
31 changes: 0 additions & 31 deletions packages/components/hooks/useDialogEsc.ts

This file was deleted.

7 changes: 7 additions & 0 deletions packages/tdesign-react/.changelog/pr-4030.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
pr_number: 4030
contributor: RylanBot
---

- fix(Dialog): 修复 `1.16.0` 的优化导致无法使用 `esc` 键关闭嵌套对话框的问题 @RylanBot ([#4030](https://github.com/Tencent/tdesign-react/pull/4030))
- undefined @RylanBot ([#4030](https://github.com/Tencent/tdesign-react/pull/4030))
Loading