Skip to content

Commit

Permalink
feat: disabled also can hover (#415)
Browse files Browse the repository at this point in the history
* feat: disabled also can hover

* test: add test case
  • Loading branch information
zombieJ authored Jul 28, 2023
1 parent b482c5c commit 9ba29dd
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 32 deletions.
11 changes: 6 additions & 5 deletions docs/examples/body-overflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,20 @@ export default () => {
htmlRegion: 'scroll',
}}
>
<span
<button
disabled
style={{
background: 'green',
color: '#FFF',
// background: 'green',
// color: '#FFF',
paddingBlock: 30,
paddingInline: 70,
opacity: 0.9,
transform: 'scale(0.6)',
display: 'inline-block',
}}
>
Target
</span>
Button Target
</button>
</Trigger>

<Trigger
Expand Down
50 changes: 37 additions & 13 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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 { flushSync } from 'react-dom';
import type { TriggerContextProps } from './context';
import TriggerContext from './context';
import useAction from './hooks/useAction';
Expand Down Expand Up @@ -307,10 +308,14 @@ export function generateTrigger(
openRef.current = mergedOpen;

const internalTriggerOpen = useEvent((nextOpen: boolean) => {
if (mergedOpen !== nextOpen) {
setMergedOpen(nextOpen);
onPopupVisibleChange?.(nextOpen);
}
// Enter or Pointer will both trigger open state change
// We only need take one to avoid duplicated change event trigger
flushSync(() => {
if (mergedOpen !== nextOpen) {
setMergedOpen(nextOpen);
onPopupVisibleChange?.(nextOpen);
}
});
});

// Trigger for delay
Expand Down Expand Up @@ -354,7 +359,9 @@ export function generateTrigger(
0, 0,
]);

const setMousePosByEvent = (event: React.MouseEvent) => {
const setMousePosByEvent = (
event: Pick<React.MouseEvent, 'clientX' | 'clientY'>,
) => {
setMousePos([event.clientX, event.clientY]);
};

Expand Down Expand Up @@ -463,21 +470,23 @@ export function generateTrigger(
hideAction,
);

// Util wrapper for trigger action
const wrapperAction = (
/**
* Util wrapper for trigger action
*/
function wrapperAction<Event extends React.SyntheticEvent>(
eventName: string,
nextOpen: boolean,
delay?: number,
preEvent?: (event: any) => void,
) => {
preEvent?: (event: Event) => void,
) {
cloneProps[eventName] = (event: any, ...args: any[]) => {
preEvent?.(event);
triggerOpen(nextOpen, delay);

// Pass to origin
originChildProps[eventName]?.(event, ...args);
};
};
}

// ======================= Action: Click ========================
const clickToShow = showActions.has('click');
Expand Down Expand Up @@ -521,9 +530,23 @@ export function generateTrigger(
let onPopupMouseLeave: VoidFunction;

if (hoverToShow) {
wrapperAction('onMouseEnter', true, mouseEnterDelay, (event) => {
setMousePosByEvent(event);
});
// Compatible with old browser which not support pointer event
wrapperAction<React.MouseEvent>(
'onMouseEnter',
true,
mouseEnterDelay,
(event) => {
setMousePosByEvent(event);
},
);
wrapperAction<React.PointerEvent>(
'onPointerEnter',
true,
mouseEnterDelay,
(event) => {
setMousePosByEvent(event);
},
);
onPopupMouseEnter = () => {
// Only trigger re-open when popup is visible
if (mergedOpen || inMotion) {
Expand All @@ -542,6 +565,7 @@ export function generateTrigger(

if (hoverToHide) {
wrapperAction('onMouseLeave', false, mouseLeaveDelay);
wrapperAction('onPointerLeave', false, mouseLeaveDelay);
onPopupMouseLeave = () => {
triggerOpen(false, mouseLeaveDelay);
};
Expand Down
48 changes: 34 additions & 14 deletions tests/basic.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,22 +131,42 @@ describe('Trigger.Basic', () => {
expect(isPopupHidden()).toBeTruthy();
});

it('hover works', () => {
const { container } = render(
<Trigger
action={['hover']}
popupAlign={placementAlignMap.left}
popup={<strong>trigger</strong>}
>
<div className="target">click</div>
</Trigger>,
);
describe('hover works', () => {
it('mouse event', () => {
const { container } = render(
<Trigger
action={['hover']}
popupAlign={placementAlignMap.left}
popup={<strong>trigger</strong>}
>
<div className="target">click</div>
</Trigger>,
);

trigger(container, '.target', 'mouseEnter');
expect(isPopupHidden()).toBeFalsy();
trigger(container, '.target', 'mouseEnter');
expect(isPopupHidden()).toBeFalsy();

trigger(container, '.target', 'mouseLeave');
expect(isPopupHidden()).toBeTruthy();
trigger(container, '.target', 'mouseLeave');
expect(isPopupHidden()).toBeTruthy();
});

it('pointer event', () => {
const { container } = render(
<Trigger
action={['hover']}
popupAlign={placementAlignMap.left}
popup={<strong>trigger</strong>}
>
<div className="target">click</div>
</Trigger>,
);

trigger(container, '.target', 'pointerEnter');
expect(isPopupHidden()).toBeFalsy();

trigger(container, '.target', 'pointerLeave');
expect(isPopupHidden()).toBeTruthy();
});
});

it('contextMenu works', () => {
Expand Down

0 comments on commit 9ba29dd

Please sign in to comment.