Skip to content

Commit 1132956

Browse files
authored
chore: auto change handler (#344)
* chore: auto change handler * chore: layoutEffect * chore: clean up * chore: clean up
1 parent fa6695f commit 1132956

File tree

4 files changed

+98
-20
lines changed

4 files changed

+98
-20
lines changed

docs/examples/body-overflow.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import React from 'react';
44
import '../../assets/index.less';
55

66
export default () => {
7+
const [open, setOpen] = React.useState(false);
8+
79
return (
810
<React.StrictMode>
911
<style
@@ -19,7 +21,13 @@ export default () => {
1921
<Trigger
2022
arrow
2123
// forceRender
22-
action="click"
24+
// action="click"
25+
popupVisible={open}
26+
onPopupVisibleChange={(next) => {
27+
console.log('Visible Change:', next);
28+
setOpen(next);
29+
}}
30+
popupTransitionName="rc-trigger-popup-zoom"
2331
popup={
2432
<div
2533
style={{
@@ -30,17 +38,23 @@ export default () => {
3038
opacity: 0.9,
3139
}}
3240
>
33-
Popup
41+
<button
42+
onClick={() => {
43+
setOpen(false);
44+
}}
45+
>
46+
Close
47+
</button>
3448
</div>
3549
}
50+
// popupVisible
3651
popupStyle={{ boxShadow: '0 0 5px red' }}
3752
popupAlign={{
3853
points: ['tc', 'bc'],
3954
overflow: {
4055
shiftX: 50,
4156
adjustY: true,
4257
},
43-
offset: [0, -10],
4458
htmlRegion: 'scroll',
4559
}}
4660
>

src/hooks/useAction.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as React from 'react';
12
import type { ActionType } from '../interface';
23

34
type ActionTypes = ActionType | ActionType[];
@@ -7,12 +8,30 @@ function toArray<T>(val?: T | T[]) {
78
}
89

910
export default function useAction(
11+
mobile: boolean,
1012
action: ActionTypes,
1113
showAction?: ActionTypes,
1214
hideAction?: ActionTypes,
1315
): [showAction: Set<ActionType>, hideAction: Set<ActionType>] {
14-
const mergedShowAction = toArray(showAction ?? action);
15-
const mergedHideAction = toArray(hideAction ?? action);
16+
return React.useMemo(() => {
17+
const mergedShowAction = toArray(showAction ?? action);
18+
const mergedHideAction = toArray(hideAction ?? action);
1619

17-
return [new Set(mergedShowAction), new Set(mergedHideAction)];
20+
const showActionSet = new Set(mergedShowAction);
21+
const hideActionSet = new Set(mergedHideAction);
22+
23+
if (mobile) {
24+
if (showActionSet.has('hover')) {
25+
showActionSet.delete('hover');
26+
showActionSet.add('click');
27+
}
28+
29+
if (hideActionSet.has('hover')) {
30+
hideActionSet.delete('hover');
31+
hideActionSet.add('click');
32+
}
33+
}
34+
35+
return [showActionSet, hideActionSet];
36+
}, [mobile, action, showAction, hideAction]);
1837
}

src/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { isDOM } from 'rc-util/lib/Dom/findDOMNode';
66
import useEvent from 'rc-util/lib/hooks/useEvent';
77
import useId from 'rc-util/lib/hooks/useId';
88
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
9+
import isMobile from 'rc-util/lib/isMobile';
910
import * as React from 'react';
1011
import type { TriggerContextProps } from './context';
1112
import TriggerContext from './context';
@@ -196,6 +197,12 @@ export function generateTrigger(
196197

197198
const mergedAutoDestroy = autoDestroy || destroyPopupOnHide || false;
198199

200+
// =========================== Mobile ===========================
201+
const [mobile, setMobile] = React.useState(false);
202+
useLayoutEffect(() => {
203+
setMobile(isMobile());
204+
}, []);
205+
199206
// ========================== Context ===========================
200207
const subPopupElements = React.useRef<Record<string, HTMLElement>>({});
201208

@@ -435,6 +442,7 @@ export function generateTrigger(
435442

436443
// =========================== Action ===========================
437444
const [showActions, hideActions] = useAction(
445+
mobile,
438446
action,
439447
showAction,
440448
hideAction,

tests/mobile.test.tsx

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,59 @@
1-
import React, { createRef } from 'react';
2-
import isMobile from 'rc-util/lib/isMobile';
31
import { act, fireEvent, render } from '@testing-library/react';
4-
import type { TriggerProps } from '../src';
2+
import isMobile from 'rc-util/lib/isMobile';
3+
import React from 'react';
54
import Trigger from '../src';
65
import { placementAlignMap } from './util';
76

87
jest.mock('rc-util/lib/isMobile');
98

10-
describe.skip('Trigger.Mobile', () => {
9+
describe('Trigger.Mobile', () => {
1110
beforeAll(() => {
1211
(isMobile as any).mockImplementation(() => true);
1312
});
1413

15-
function getTrigger(
16-
props?: Partial<
17-
TriggerProps & React.ClassAttributes<InstanceType<typeof Trigger>>
18-
>,
19-
) {
14+
beforeEach(() => {
15+
jest.useFakeTimers();
16+
});
17+
18+
afterEach(() => {
19+
jest.clearAllTimers();
20+
jest.useRealTimers();
21+
});
22+
23+
function flush() {
24+
act(() => {
25+
jest.runAllTimers();
26+
});
27+
}
28+
29+
it('auto change hover to click', () => {
30+
render(
31+
<Trigger
32+
popupAlign={placementAlignMap.left}
33+
popup={<strong>trigger</strong>}
34+
>
35+
<div className="target" />
36+
</Trigger>,
37+
);
38+
39+
flush();
40+
expect(document.querySelector('.rc-trigger-popup')).toBeFalsy();
41+
42+
// Hover not work
43+
fireEvent.mouseEnter(document.querySelector('.target'));
44+
flush();
45+
expect(document.querySelector('.rc-trigger-popup')).toBeFalsy();
46+
47+
// Click work
48+
fireEvent.click(document.querySelector('.target'));
49+
flush();
50+
expect(document.querySelector('.rc-trigger-popup')).toBeTruthy();
51+
});
52+
53+
// ====================================================================================
54+
// ZombieJ: back when we plan to support mobile
55+
56+
function getTrigger(props?: any) {
2057
return (
2158
<Trigger
2259
action={['click']}
@@ -32,7 +69,7 @@ describe.skip('Trigger.Mobile', () => {
3269
);
3370
}
3471

35-
it('mobile config', () => {
72+
it.skip('mobile config', () => {
3673
const { container } = render(
3774
getTrigger({
3875
mobile: {
@@ -53,7 +90,7 @@ describe.skip('Trigger.Mobile', () => {
5390
});
5491
});
5592

56-
it('popupRender', () => {
93+
it.skip('popupRender', () => {
5794
const { container } = render(
5895
getTrigger({
5996
mobile: {
@@ -71,8 +108,8 @@ describe.skip('Trigger.Mobile', () => {
71108
expect(document.querySelector('.rc-trigger-popup')).toMatchSnapshot();
72109
});
73110

74-
it('click inside not close', () => {
75-
const triggerRef = createRef<InstanceType<typeof Trigger>>();
111+
it.skip('click inside not close', () => {
112+
const triggerRef = React.createRef<any>();
76113
const { container } = render(getTrigger({ ref: triggerRef }));
77114
fireEvent.click(container.querySelector('.target'));
78115
expect(triggerRef.current.state.popupVisible).toBeTruthy();
@@ -86,7 +123,7 @@ describe.skip('Trigger.Mobile', () => {
86123
expect(triggerRef.current.state.popupVisible).toBeFalsy();
87124
});
88125

89-
it('legacy array children', () => {
126+
it.skip('legacy array children', () => {
90127
const { container } = render(
91128
getTrigger({
92129
popup: [<div key={0}>Light</div>, <div key={1}>Bamboo</div>],

0 commit comments

Comments
 (0)