Skip to content

Commit

Permalink
chore: auto change handler (#344)
Browse files Browse the repository at this point in the history
* chore: auto change handler

* chore: layoutEffect

* chore: clean up

* chore: clean up
  • Loading branch information
zombieJ authored Mar 17, 2023
1 parent fa6695f commit 1132956
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 20 deletions.
20 changes: 17 additions & 3 deletions docs/examples/body-overflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import React from 'react';
import '../../assets/index.less';

export default () => {
const [open, setOpen] = React.useState(false);

return (
<React.StrictMode>
<style
Expand All @@ -19,7 +21,13 @@ export default () => {
<Trigger
arrow
// forceRender
action="click"
// action="click"
popupVisible={open}
onPopupVisibleChange={(next) => {
console.log('Visible Change:', next);
setOpen(next);
}}
popupTransitionName="rc-trigger-popup-zoom"
popup={
<div
style={{
Expand All @@ -30,17 +38,23 @@ export default () => {
opacity: 0.9,
}}
>
Popup
<button
onClick={() => {
setOpen(false);
}}
>
Close
</button>
</div>
}
// popupVisible
popupStyle={{ boxShadow: '0 0 5px red' }}
popupAlign={{
points: ['tc', 'bc'],
overflow: {
shiftX: 50,
adjustY: true,
},
offset: [0, -10],
htmlRegion: 'scroll',
}}
>
Expand Down
25 changes: 22 additions & 3 deletions src/hooks/useAction.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as React from 'react';
import type { ActionType } from '../interface';

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

export default function useAction(
mobile: boolean,
action: ActionTypes,
showAction?: ActionTypes,
hideAction?: ActionTypes,
): [showAction: Set<ActionType>, hideAction: Set<ActionType>] {
const mergedShowAction = toArray(showAction ?? action);
const mergedHideAction = toArray(hideAction ?? action);
return React.useMemo(() => {
const mergedShowAction = toArray(showAction ?? action);
const mergedHideAction = toArray(hideAction ?? action);

return [new Set(mergedShowAction), new Set(mergedHideAction)];
const showActionSet = new Set(mergedShowAction);
const hideActionSet = new Set(mergedHideAction);

if (mobile) {
if (showActionSet.has('hover')) {
showActionSet.delete('hover');
showActionSet.add('click');
}

if (hideActionSet.has('hover')) {
hideActionSet.delete('hover');
hideActionSet.add('click');
}
}

return [showActionSet, hideActionSet];
}, [mobile, action, showAction, hideAction]);
}
8 changes: 8 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { isDOM } from 'rc-util/lib/Dom/findDOMNode';
import useEvent from 'rc-util/lib/hooks/useEvent';
import useId from 'rc-util/lib/hooks/useId';
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
import isMobile from 'rc-util/lib/isMobile';
import * as React from 'react';
import type { TriggerContextProps } from './context';
import TriggerContext from './context';
Expand Down Expand Up @@ -196,6 +197,12 @@ export function generateTrigger(

const mergedAutoDestroy = autoDestroy || destroyPopupOnHide || false;

// =========================== Mobile ===========================
const [mobile, setMobile] = React.useState(false);
useLayoutEffect(() => {
setMobile(isMobile());
}, []);

// ========================== Context ===========================
const subPopupElements = React.useRef<Record<string, HTMLElement>>({});

Expand Down Expand Up @@ -435,6 +442,7 @@ export function generateTrigger(

// =========================== Action ===========================
const [showActions, hideActions] = useAction(
mobile,
action,
showAction,
hideAction,
Expand Down
65 changes: 51 additions & 14 deletions tests/mobile.test.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,59 @@
import React, { createRef } from 'react';
import isMobile from 'rc-util/lib/isMobile';
import { act, fireEvent, render } from '@testing-library/react';
import type { TriggerProps } from '../src';
import isMobile from 'rc-util/lib/isMobile';
import React from 'react';
import Trigger from '../src';
import { placementAlignMap } from './util';

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

describe.skip('Trigger.Mobile', () => {
describe('Trigger.Mobile', () => {
beforeAll(() => {
(isMobile as any).mockImplementation(() => true);
});

function getTrigger(
props?: Partial<
TriggerProps & React.ClassAttributes<InstanceType<typeof Trigger>>
>,
) {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});

function flush() {
act(() => {
jest.runAllTimers();
});
}

it('auto change hover to click', () => {
render(
<Trigger
popupAlign={placementAlignMap.left}
popup={<strong>trigger</strong>}
>
<div className="target" />
</Trigger>,
);

flush();
expect(document.querySelector('.rc-trigger-popup')).toBeFalsy();

// Hover not work
fireEvent.mouseEnter(document.querySelector('.target'));
flush();
expect(document.querySelector('.rc-trigger-popup')).toBeFalsy();

// Click work
fireEvent.click(document.querySelector('.target'));
flush();
expect(document.querySelector('.rc-trigger-popup')).toBeTruthy();
});

// ====================================================================================
// ZombieJ: back when we plan to support mobile

function getTrigger(props?: any) {
return (
<Trigger
action={['click']}
Expand All @@ -32,7 +69,7 @@ describe.skip('Trigger.Mobile', () => {
);
}

it('mobile config', () => {
it.skip('mobile config', () => {
const { container } = render(
getTrigger({
mobile: {
Expand All @@ -53,7 +90,7 @@ describe.skip('Trigger.Mobile', () => {
});
});

it('popupRender', () => {
it.skip('popupRender', () => {
const { container } = render(
getTrigger({
mobile: {
Expand All @@ -71,8 +108,8 @@ describe.skip('Trigger.Mobile', () => {
expect(document.querySelector('.rc-trigger-popup')).toMatchSnapshot();
});

it('click inside not close', () => {
const triggerRef = createRef<InstanceType<typeof Trigger>>();
it.skip('click inside not close', () => {
const triggerRef = React.createRef<any>();
const { container } = render(getTrigger({ ref: triggerRef }));
fireEvent.click(container.querySelector('.target'));
expect(triggerRef.current.state.popupVisible).toBeTruthy();
Expand All @@ -86,7 +123,7 @@ describe.skip('Trigger.Mobile', () => {
expect(triggerRef.current.state.popupVisible).toBeFalsy();
});

it('legacy array children', () => {
it.skip('legacy array children', () => {
const { container } = render(
getTrigger({
popup: [<div key={0}>Light</div>, <div key={1}>Bamboo</div>],
Expand Down

0 comments on commit 1132956

Please sign in to comment.