Skip to content

Commit 5e39d18

Browse files
authored
feat: trigger support nativeElement (#435)
1 parent 2f8e6e5 commit 5e39d18

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

src/index.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
1010
import isMobile from 'rc-util/lib/isMobile';
1111
import * as React from 'react';
1212
import { flushSync } from 'react-dom';
13+
import Popup from './Popup';
14+
import TriggerWrapper from './TriggerWrapper';
1315
import type { TriggerContextProps } from './context';
1416
import TriggerContext from './context';
1517
import useAction from './hooks/useAction';
@@ -25,18 +27,17 @@ import type {
2527
BuildInPlacements,
2628
TransitionNameType,
2729
} from './interface';
28-
import Popup from './Popup';
29-
import TriggerWrapper from './TriggerWrapper';
3030
import { getAlignPopupClassName, getMotion } from './util';
3131

3232
export type {
33-
BuildInPlacements,
34-
AlignType,
3533
ActionType,
34+
AlignType,
3635
ArrowTypeOuter as ArrowType,
36+
BuildInPlacements,
3737
};
3838

3939
export interface TriggerRef {
40+
nativeElement: HTMLElement;
4041
forceAlign: VoidFunction;
4142
}
4243

@@ -251,9 +252,13 @@ export function generateTrigger(
251252
// Use state to control here since `useRef` update not trigger render
252253
const [targetEle, setTargetEle] = React.useState<HTMLElement>(null);
253254

255+
// Used for forwardRef target. Not use internal
256+
const externalForwardRef = React.useRef<HTMLElement>(null);
257+
254258
const setTargetRef = useEvent((node: HTMLElement) => {
255259
if (isDOM(node) && targetEle !== node) {
256260
setTargetEle(node);
261+
externalForwardRef.current = node;
257262
}
258263
});
259264

@@ -448,7 +453,9 @@ export function generateTrigger(
448453
alignPoint,
449454
]);
450455

456+
// ============================ Refs ============================
451457
React.useImperativeHandle(ref, () => ({
458+
nativeElement: externalForwardRef.current,
452459
forceAlign: triggerAlign,
453460
}));
454461

tests/ref.test.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* eslint-disable max-classes-per-file */
2+
3+
import { cleanup, render } from '@testing-library/react';
4+
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
5+
import React from 'react';
6+
import Trigger, { type TriggerRef } from '../src';
7+
8+
describe('Trigger.Ref', () => {
9+
beforeAll(() => {
10+
spyElementPrototypes(HTMLElement, {
11+
offsetParent: {
12+
get: () => document.body,
13+
},
14+
});
15+
});
16+
17+
beforeEach(() => {
18+
jest.useFakeTimers();
19+
});
20+
21+
afterEach(() => {
22+
cleanup();
23+
jest.useRealTimers();
24+
});
25+
26+
it('support nativeElement', () => {
27+
const triggerRef = React.createRef<TriggerRef>();
28+
29+
const { container } = render(
30+
<Trigger ref={triggerRef} popup={<div />}>
31+
<button />
32+
</Trigger>,
33+
);
34+
35+
expect(triggerRef.current.nativeElement).toBe(
36+
container.querySelector('button'),
37+
);
38+
});
39+
});

0 commit comments

Comments
 (0)