mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[Flare] Remove delay props from Hover (#16248)
Moving working with delays into user-space.
This commit is contained in:
@@ -37,16 +37,6 @@ type HoverEvent = {
|
||||
|
||||
## Props
|
||||
|
||||
### delayHoverEnd: number
|
||||
|
||||
The duration of the delay between when hover ends and when `onHoverEnd` is
|
||||
called.
|
||||
|
||||
### delayHoverStart: number
|
||||
|
||||
The duration of the delay between when hover starts and when `onHoverStart` is
|
||||
called.
|
||||
|
||||
### disabled: boolean
|
||||
|
||||
Disables all `Hover` events.
|
||||
@@ -58,19 +48,15 @@ Called when the element changes hover state (i.e., after `onHoverStart` and
|
||||
|
||||
### onHoverEnd: (e: HoverEvent) => void
|
||||
|
||||
Called once the element is no longer hovered. It will be cancelled if the
|
||||
pointer leaves the element before the `delayHoverStart` threshold is exceeded.
|
||||
Called once the element is no longer hovered.
|
||||
|
||||
### onHoverMove: (e: HoverEvent) => void
|
||||
|
||||
Called when the pointer moves within the hit bounds of the element. `onHoverMove` is
|
||||
called immediately and doesn't wait for delayed `onHoverStart`.
|
||||
Called when the pointer moves within the hit bounds of the element.
|
||||
|
||||
### onHoverStart: (e: HoverEvent) => void
|
||||
|
||||
Called once the element is hovered. It will not be called if the pointer leaves
|
||||
the element before the `delayHoverStart` threshold is exceeded. And it will not
|
||||
be called more than once before `onHoverEnd` is called.
|
||||
Called once the element is hovered.
|
||||
|
||||
### preventDefault: boolean = true
|
||||
|
||||
|
||||
+2
-43
@@ -24,8 +24,6 @@ type HoverListenerProps = {|
|
||||
|
||||
type HoverProps = {
|
||||
disabled: boolean,
|
||||
delayHoverEnd: number,
|
||||
delayHoverStart: number,
|
||||
preventDefault: boolean,
|
||||
};
|
||||
|
||||
@@ -55,9 +53,6 @@ type HoverEvent = {|
|
||||
y: null | number,
|
||||
|};
|
||||
|
||||
const DEFAULT_HOVER_END_DELAY_MS = 0;
|
||||
const DEFAULT_HOVER_START_DELAY_MS = 0;
|
||||
|
||||
const targetEventTypes = [
|
||||
'pointerover',
|
||||
'pointermove',
|
||||
@@ -136,7 +131,7 @@ function dispatchHoverStartEvents(
|
||||
state.hoverEndTimeout = null;
|
||||
}
|
||||
|
||||
const activate = () => {
|
||||
if (!state.isActiveHovered) {
|
||||
state.isActiveHovered = true;
|
||||
const syntheticEvent = createHoverEvent(
|
||||
event,
|
||||
@@ -146,22 +141,6 @@ function dispatchHoverStartEvents(
|
||||
);
|
||||
context.dispatchEvent('onHoverStart', syntheticEvent, UserBlockingEvent);
|
||||
dispatchHoverChangeEvent(event, context, props, state);
|
||||
};
|
||||
|
||||
if (!state.isActiveHovered) {
|
||||
const delayHoverStart = calculateDelayMS(
|
||||
props.delayHoverStart,
|
||||
0,
|
||||
DEFAULT_HOVER_START_DELAY_MS,
|
||||
);
|
||||
if (delayHoverStart > 0) {
|
||||
state.hoverStartTimeout = context.setTimeout(() => {
|
||||
state.hoverStartTimeout = null;
|
||||
activate();
|
||||
}, delayHoverStart);
|
||||
} else {
|
||||
activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +167,7 @@ function dispatchHoverEndEvents(
|
||||
state.hoverStartTimeout = null;
|
||||
}
|
||||
|
||||
const deactivate = () => {
|
||||
if (state.isActiveHovered) {
|
||||
state.isActiveHovered = false;
|
||||
|
||||
const syntheticEvent = createHoverEvent(
|
||||
@@ -202,29 +181,9 @@ function dispatchHoverEndEvents(
|
||||
state.hoverTarget = null;
|
||||
state.ignoreEmulatedMouseEvents = false;
|
||||
state.isTouched = false;
|
||||
};
|
||||
|
||||
if (state.isActiveHovered) {
|
||||
const delayHoverEnd = calculateDelayMS(
|
||||
props.delayHoverEnd,
|
||||
0,
|
||||
DEFAULT_HOVER_END_DELAY_MS,
|
||||
);
|
||||
if (delayHoverEnd > 0) {
|
||||
state.hoverEndTimeout = context.setTimeout(() => {
|
||||
deactivate();
|
||||
}, delayHoverEnd);
|
||||
} else {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateDelayMS(delay: ?number, min = 0, fallback = 0) {
|
||||
const maybeNumber = delay == null ? null : delay;
|
||||
return Math.max(min, maybeNumber != null ? maybeNumber : fallback);
|
||||
}
|
||||
|
||||
function unmountResponder(
|
||||
context: ReactDOMResponderContext,
|
||||
props: HoverProps,
|
||||
|
||||
@@ -167,97 +167,6 @@ describe('Hover event responder', () => {
|
||||
);
|
||||
expect(onHoverStart).not.toBeCalled();
|
||||
});
|
||||
|
||||
describe('delayHoverStart', () => {
|
||||
it('can be configured', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverStart: onHoverStart,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
responders={<HoverResponder delayHoverStart={2000} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
jest.advanceTimersByTime(1999);
|
||||
expect(onHoverStart).not.toBeCalled();
|
||||
jest.advanceTimersByTime(1);
|
||||
expect(onHoverStart).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('is reset if "pointerout" is dispatched during a delay', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverStart: onHoverStart,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
responders={<HoverResponder delayHoverStart={500} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
jest.advanceTimersByTime(499);
|
||||
ref.current.dispatchEvent(createEvent('pointerout'));
|
||||
jest.advanceTimersByTime(1);
|
||||
expect(onHoverStart).not.toBeCalled();
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
jest.runAllTimers();
|
||||
expect(onHoverStart).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('onHoverStart is called synchronously if delay is 0ms', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverStart: onHoverStart,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
responders={<HoverResponder delayHoverStart={0} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
expect(onHoverStart).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('onHoverStart is only called once per active hover', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverStart: onHoverStart,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
responders={
|
||||
<HoverResponder delayHoverStart={500} delayHoverEnd={100} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
jest.advanceTimersByTime(500);
|
||||
expect(onHoverStart).toHaveBeenCalledTimes(1);
|
||||
ref.current.dispatchEvent(createEvent('pointerout'));
|
||||
jest.advanceTimersByTime(10);
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
jest.runAllTimers();
|
||||
expect(onHoverStart).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onHoverChange', () => {
|
||||
@@ -399,114 +308,6 @@ describe('Hover event responder', () => {
|
||||
ref.current.dispatchEvent(createEvent('mouseout'));
|
||||
expect(onHoverEnd).not.toBeCalled();
|
||||
});
|
||||
|
||||
describe('delayHoverEnd', () => {
|
||||
it('can be configured', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverEnd,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
responders={<HoverResponder delayHoverEnd={2000} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
ref.current.dispatchEvent(createEvent('pointerout'));
|
||||
jest.advanceTimersByTime(1999);
|
||||
expect(onHoverEnd).not.toBeCalled();
|
||||
jest.advanceTimersByTime(1);
|
||||
expect(onHoverEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('delayHoverEnd is called synchronously if delay is 0ms', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverEnd,
|
||||
});
|
||||
return (
|
||||
<div ref={ref} responders={<HoverResponder delayHoverEnd={0} />} />
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
ref.current.dispatchEvent(createEvent('pointerout'));
|
||||
expect(onHoverEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('onHoverEnd is only called once per active hover', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverEnd,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
responders={<HoverResponder delayHoverEnd={500} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
ref.current.dispatchEvent(createEvent('pointerout'));
|
||||
jest.advanceTimersByTime(499);
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
jest.advanceTimersByTime(100);
|
||||
ref.current.dispatchEvent(createEvent('pointerout'));
|
||||
jest.runAllTimers();
|
||||
expect(onHoverEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('onHoverEnd is not called if "pointerover" is dispatched during a delay', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverEnd,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
responders={<HoverResponder delayHoverEnd={500} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
ref.current.dispatchEvent(createEvent('pointerout'));
|
||||
jest.advanceTimersByTime(499);
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
jest.advanceTimersByTime(1);
|
||||
expect(onHoverEnd).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('onHoverEnd is not called if there was no active hover', () => {
|
||||
const Component = () => {
|
||||
useHoverListener({
|
||||
onHoverEnd,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
responders={
|
||||
<HoverResponder delayHoverStart={500} delayHoverEnd={100} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
ref.current.dispatchEvent(createEvent('pointerover'));
|
||||
ref.current.dispatchEvent(createEvent('pointerout'));
|
||||
jest.runAllTimers();
|
||||
expect(onHoverEnd).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onHoverMove', () => {
|
||||
|
||||
Reference in New Issue
Block a user