diff --git a/package.json b/package.json index 471dddca..e74af135 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "docs:deploy": "gh-pages -d .doc", "compile": "father build && lessc assets/index.less assets/index.css && lessc assets/bootstrap.less assets/bootstrap.css", "deploy": "npm run docs:build && npm run docs:deploy", - "prepublishOnly": "npm run compile && np --yolo --no-publish", + "prepublishOnly": "npm run compile && np --yolo --no-publish --branch=9.0.x", "lint": "eslint src/ --ext .ts,.tsx,.jsx,.js,.md", "lint:tsc": "tsc -p tsconfig.json --noEmit", "prettier": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"", diff --git a/src/Dialog/Content/Panel.tsx b/src/Dialog/Content/Panel.tsx index 8b35b590..4dfffa14 100644 --- a/src/Dialog/Content/Panel.tsx +++ b/src/Dialog/Content/Panel.tsx @@ -48,14 +48,14 @@ const Panel = React.forwardRef((props, ref) => { React.useImperativeHandle(ref, () => ({ focus: () => { - sentinelStartRef.current?.focus(); + sentinelStartRef.current?.focus({ preventScroll: true }); }, changeActive: (next) => { const { activeElement } = document; if (next && activeElement === sentinelEndRef.current) { - sentinelStartRef.current.focus(); + sentinelStartRef.current.focus({ preventScroll: true }); } else if (!next && activeElement === sentinelStartRef.current) { - sentinelEndRef.current.focus(); + sentinelEndRef.current.focus({ preventScroll: true }); } }, })); diff --git a/src/Dialog/index.tsx b/src/Dialog/index.tsx index e708d36d..a225204d 100644 --- a/src/Dialog/index.tsx +++ b/src/Dialog/index.tsx @@ -129,10 +129,8 @@ export default function Dialog(props: IDialogPropTypes) { } // keep focus inside dialog - if (visible) { - if (e.keyCode === KeyCode.TAB) { - contentRef.current.changeActive(!e.shiftKey); - } + if (visible && e.keyCode === KeyCode.TAB) { + contentRef.current.changeActive(!e.shiftKey); } } diff --git a/tests/index.spec.tsx b/tests/index.spec.tsx index d90c4421..ac6cd193 100644 --- a/tests/index.spec.tsx +++ b/tests/index.spec.tsx @@ -1,19 +1,30 @@ /* eslint-disable react/no-render-return-value, max-classes-per-file, func-names, no-console */ -import React, { cloneElement, useEffect } from 'react'; -import { act } from 'react-dom/test-utils'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import type { ReactWrapper } from 'enzyme'; import { mount } from 'enzyme'; +import { Provider } from 'rc-motion'; +import React, { cloneElement, useEffect } from 'react'; +import { act } from 'react-dom/test-utils'; import KeyCode from 'rc-util/lib/KeyCode'; import type { DialogProps } from '../src'; import Dialog from '../src'; describe('dialog', () => { + async function runFakeTimer() { + for (let i = 0; i < 100; i += 1) { + await act(async () => { + jest.advanceTimersByTime(100); + await Promise.resolve(); + }); + } + } + beforeEach(() => { jest.useFakeTimers(); }); afterEach(() => { + jest.clearAllTimers(); jest.useRealTimers(); }); @@ -252,15 +263,17 @@ describe('dialog', () => { }); it('trap focus after shift-tabbing', () => { - const wrapper = mount(, { attachTo: document.body }); - wrapper.find('.rc-dialog-wrap').simulate('keyDown', { + render(); + + document.querySelector('.rc-dialog > div').focus(); + + fireEvent.keyDown(document.querySelector('.rc-dialog-wrap'), { keyCode: KeyCode.TAB, + key: 'Tab', shiftKey: true, }); - const sentinelEnd = document.querySelectorAll('.rc-dialog-content + div')[0]; + const sentinelEnd = document.querySelector('.rc-dialog-content + div'); expect(document.activeElement).toBe(sentinelEnd); - - wrapper.unmount(); }); }); diff --git a/tests/setup.js b/tests/setup.js index 9d51ef44..fa14f0a0 100644 --- a/tests/setup.js +++ b/tests/setup.js @@ -1,5 +1,16 @@ /* eslint-disable no-console */ -global.requestAnimationFrame = cb => setTimeout(cb, 0); +global.requestAnimationFrame = (cb) => { + return global.setTimeout(cb, 0); +}; +global.cancelAnimationFrame = (cb) => { + return global.clearTimeout(cb, 0); +}; +window.requestAnimationFrame = (cb) => { + return window.setTimeout(cb, 0); +}; +window.cancelAnimationFrame = (cb) => { + return window.clearTimeout(cb, 0); +}; const originError = console.error; const ignoreList = [ @@ -7,7 +18,7 @@ const ignoreList = [ 'Warning: unmountComponentAtNode():', ]; console.error = (...args) => { - if (ignoreList.some(str => args[0].includes(str))) { + if (ignoreList.some((str) => args[0].includes(str))) { return; }