Skip to content

Commit 7d05f7c

Browse files
authored
feat: drawer support panelRef (#424)
* feat: drawer support panelRef * chore: fix lint * chore: bump father
1 parent 6ca942c commit 7d05f7c

File tree

6 files changed

+95
-48
lines changed

6 files changed

+95
-48
lines changed

.fatherrc.js

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
export default {
2-
cjs: 'babel',
3-
esm: { type: 'babel', importLibToEs: true },
4-
preCommit: {
5-
eslint: true,
6-
prettier: true,
7-
},
8-
runtimeHelpers: true,
9-
};
1+
import { defineConfig } from 'father';
2+
3+
export default defineConfig({
4+
plugins: ['@rc-component/father-plugin'],
5+
});

package.json

+21-22
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,40 @@
1515
"drawer-animation"
1616
],
1717
"homepage": "https://github.com/react-component/drawer",
18-
"author": "[email protected]",
18+
"bugs": {
19+
"url": "https://github.com/react-component/drawer/issues"
20+
},
1921
"repository": {
2022
"type": "git",
2123
"url": "https://github.com/react-component/drawer.git"
2224
},
23-
"bugs": {
24-
"url": "https://github.com/react-component/drawer/issues"
25-
},
25+
"license": "MIT",
26+
"author": "[email protected]",
27+
"main": "./lib/index",
28+
"module": "./es/index",
2629
"files": [
2730
"lib",
2831
"assets/*.css",
2932
"es"
3033
],
31-
"license": "MIT",
32-
"main": "./lib/index",
33-
"module": "./es/index",
3434
"scripts": {
35-
"start": "dumi dev",
3635
"build": "dumi build",
37-
"compile": "father-build && lessc assets/index.less assets/index.css",
38-
"prepublishOnly": "npm run compile && np --no-cleanup --yolo --no-publish",
36+
"compile": "father build && lessc assets/index.less assets/index.css",
3937
"lint": "eslint src/ --ext .tsx,.ts",
40-
"test": "umi-test",
41-
"now-build": "npm run build"
42-
},
43-
"peerDependencies": {
44-
"react": ">=16.9.0",
45-
"react-dom": ">=16.9.0"
38+
"now-build": "npm run build",
39+
"prepublishOnly": "npm run compile && np --no-cleanup --yolo --no-publish",
40+
"start": "dumi dev",
41+
"test": "rc-test"
4642
},
4743
"dependencies": {
4844
"@babel/runtime": "^7.10.1",
4945
"@rc-component/portal": "^1.1.1",
5046
"classnames": "^2.2.6",
5147
"rc-motion": "^2.6.1",
52-
"rc-util": "^5.21.2"
48+
"rc-util": "^5.36.0"
5349
},
5450
"devDependencies": {
51+
"@rc-component/father-plugin": "^1.0.0",
5552
"@ant-design/icons": "^4.7.0",
5653
"@testing-library/jest-dom": "^5.11.9",
5754
"@testing-library/react": "^14.0.0",
@@ -61,19 +58,21 @@
6158
"@types/react": "^18.0.0",
6259
"@types/react-dom": "^18.0.0",
6360
"@types/warning": "^3.0.0",
64-
"@umijs/fabric": "^2.0.0",
65-
"@umijs/test": "^3.5.23",
61+
"rc-test": "^7.0.9",
6662
"antd": "^4.20.2",
6763
"dumi": "^2.2.0",
6864
"eslint": "^7.0.0",
69-
"father": "^2.30.21",
70-
"father-build": "^1.22.1",
65+
"father": "^4.0.0",
7166
"glob": "^7.1.6",
7267
"less": "^3.10.3",
7368
"np": "^7.5.0",
74-
"prettier": "^2.6.2",
69+
"prettier": "^3.0.0",
7570
"react": "^18.0.0",
7671
"react-dom": "^18.0.0",
7772
"typescript": "^4.6.4"
73+
},
74+
"peerDependencies": {
75+
"react": ">=16.9.0",
76+
"react-dom": ">=16.9.0"
7877
}
7978
}

src/Drawer.tsx

+32-16
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1-
import * as React from 'react';
2-
import Portal from '@rc-component/portal';
31
import type { PortalProps } from '@rc-component/portal';
2+
import Portal from '@rc-component/portal';
43
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
5-
import DrawerPopup from './DrawerPopup';
4+
import * as React from 'react';
5+
import { RefContext } from './context';
6+
import type { DrawerPanelEvents } from './DrawerPanel';
67
import type { DrawerPopupProps } from './DrawerPopup';
8+
import DrawerPopup from './DrawerPopup';
79
import { warnCheck } from './util';
8-
import type { DrawerPanelEvents } from './DrawerPanel';
910

1011
export type Placement = 'left' | 'top' | 'right' | 'bottom';
1112

1213
export interface DrawerProps
13-
extends Omit<DrawerPopupProps, 'prefixCls' | 'inline' | 'scrollLocker'>, DrawerPanelEvents {
14+
extends Omit<DrawerPopupProps, 'prefixCls' | 'inline' | 'scrollLocker'>,
15+
DrawerPanelEvents {
1416
prefixCls?: string;
1517
open?: boolean;
1618
onClose?: (e: React.MouseEvent | React.KeyboardEvent) => void;
1719
destroyOnClose?: boolean;
1820
getContainer?: PortalProps['getContainer'];
21+
panelRef?: React.Ref<HTMLDivElement>;
1922
}
2023

2124
const Drawer: React.FC<DrawerProps> = props => {
@@ -38,6 +41,9 @@ const Drawer: React.FC<DrawerProps> = props => {
3841
onClick,
3942
onKeyDown,
4043
onKeyUp,
44+
45+
// Refs
46+
panelRef,
4147
} = props;
4248

4349
const [animatedVisible, setAnimatedVisible] = React.useState(false);
@@ -57,7 +63,7 @@ const Drawer: React.FC<DrawerProps> = props => {
5763
const mergedOpen = mounted ? open : false;
5864

5965
// ============================ Focus =============================
60-
const panelRef = React.useRef<HTMLDivElement>();
66+
const popupRef = React.useRef<HTMLDivElement>();
6167

6268
const lastActiveRef = React.useRef<HTMLElement>();
6369
useLayoutEffect(() => {
@@ -75,12 +81,20 @@ const Drawer: React.FC<DrawerProps> = props => {
7581
if (
7682
!nextVisible &&
7783
lastActiveRef.current &&
78-
!panelRef.current?.contains(lastActiveRef.current)
84+
!popupRef.current?.contains(lastActiveRef.current)
7985
) {
8086
lastActiveRef.current?.focus({ preventScroll: true });
8187
}
8288
};
8389

90+
// =========================== Context ============================
91+
const refContext = React.useMemo(
92+
() => ({
93+
panel: panelRef,
94+
}),
95+
[panelRef],
96+
);
97+
8498
// ============================ Render ============================
8599
if (!forceRender && !animatedVisible && !mergedOpen && destroyOnClose) {
86100
return null;
@@ -106,19 +120,21 @@ const Drawer: React.FC<DrawerProps> = props => {
106120
maskClosable,
107121
inline: getContainer === false,
108122
afterOpenChange: internalAfterOpenChange,
109-
ref: panelRef,
123+
ref: popupRef,
110124
...eventHandlers,
111125
};
112126

113127
return (
114-
<Portal
115-
open={mergedOpen || forceRender || animatedVisible}
116-
autoDestroy={false}
117-
getContainer={getContainer}
118-
autoLock={mask && (mergedOpen || animatedVisible)}
119-
>
120-
<DrawerPopup {...drawerPopupProps} />
121-
</Portal>
128+
<RefContext.Provider value={refContext}>
129+
<Portal
130+
open={mergedOpen || forceRender || animatedVisible}
131+
autoDestroy={false}
132+
getContainer={getContainer}
133+
autoLock={mask && (mergedOpen || animatedVisible)}
134+
>
135+
<DrawerPopup {...drawerPopupProps} />
136+
</Portal>
137+
</RefContext.Provider>
122138
);
123139
};
124140

src/DrawerPanel.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import classNames from 'classnames';
2+
import { useComposeRef } from 'rc-util';
23
import * as React from 'react';
4+
import { RefContext } from './context';
35

46
export interface DrawerPanelRef {
57
focus: VoidFunction;
@@ -48,6 +50,9 @@ const DrawerPanel = (props: DrawerPanelProps) => {
4850
onKeyUp,
4951
};
5052

53+
const { panel: panelRef } = React.useContext(RefContext);
54+
const mergedRef = useComposeRef(panelRef, containerRef);
55+
5156
// =============================== Render ===============================
5257

5358
return (
@@ -60,7 +65,7 @@ const DrawerPanel = (props: DrawerPanelProps) => {
6065
}}
6166
aria-modal="true"
6267
role="dialog"
63-
ref={containerRef}
68+
ref={mergedRef}
6469
{...eventHandlers}
6570
>
6671
{children}

src/context.ts

+6
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,10 @@ export interface DrawerContextProps {
88

99
const DrawerContext = React.createContext<DrawerContextProps>(null);
1010

11+
export interface RefContextProps {
12+
panel?: React.Ref<HTMLDivElement>;
13+
}
14+
15+
export const RefContext = React.createContext<RefContextProps>({});
16+
1117
export default DrawerContext;

tests/ref.spec.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { act, cleanup, render } from '@testing-library/react';
2+
import React from 'react';
3+
import Drawer from '../src';
4+
5+
describe('Drawer.ref', () => {
6+
beforeEach(() => {
7+
jest.useFakeTimers();
8+
});
9+
10+
afterEach(() => {
11+
jest.useRealTimers();
12+
cleanup();
13+
});
14+
15+
it('support panelRef', () => {
16+
const panelRef = React.createRef<HTMLDivElement>();
17+
render(<Drawer open panelRef={panelRef} />);
18+
19+
act(() => {
20+
jest.runAllTimers();
21+
});
22+
23+
expect(panelRef.current).toHaveClass('rc-drawer-content');
24+
});
25+
});

0 commit comments

Comments
 (0)