useInteractivity
The useInteractivity hook adds mouse/touch events to HTML elements, returning state that minimizes the need for calculations.
Installation
Yarn
yarn add @jwdinker/interactivity-hooks
NPM
npm install @jwdinker/interactivity-hooks
Usage
With Re-rendering
import useInteractivity from "@jwdinker/interactivity-hooks";
import { useRef } from "react";
const MyInteractiveComponent = () => {
const ref = useRef();
const [state] = useInteractivity(ref);
const {
move: {
continued: { x, y }
}
} = state;
return (
<div style={{ width: "100%", height: "100%" }}>
<div
ref={ref}
style={{ transform: `translate3d(${x}px,${y}px,0)`, width: "100px" }}
>
<div
style={{
background: "white",
borderRadius: "4px",
boxShadow:
"0px 5px 15px rgba(54, 64, 70, 0.05), 0px 1px 3px rgba(16, 16, 16, 0.1)"
}}
>
<div style={{ height: "100px", width: "100px" }}>Move Me Around</div>
</div>
</div>
</div>
);
};
Preventing Rerenders
Since touch / mouse events can trigger expensive rerenders, setting the imperative option to true
prevents
rerenders and allows you to access the state through callbacks. This is useful with animation libraries that
operate directly on DOM nodes.
import useInteractivity from "@jwdinker/interactivity-hooks";
import { useRef, useState } from "react";
const MyInteractiveComponent = () => {
const [coordinates, setCoordinates] = useState([0, 0]);
const ref = useRef();
useInteractivity(ref, {
imperative: true,
onInteraction: ({
move: {
continued: { x, y }
}
}) => {
if (coordinates.x > 100) {
setCoordinates([x, y]);
}
}
});
return (
<div style={{ width: "100%", height: "100%" }}>
<div
ref={ref}
style={{
transform: `translate3d(${coordinates.x}px,${coordinates.y}px,0)`,
width: "100px"
}}
>
<div
style={{
background: "white",
borderRadius: "4px",
boxShadow:
"0px 5px 15px rgba(54, 64, 70, 0.05), 0px 1px 3px rgba(16, 16, 16, 0.1)"
}}
>
<div style={{ height: "100px", width: "100px" }}>Move Me Around</div>
</div>
</div>
</div>
);
};
Arguments
Argument 1
Property | Type | Default | Description |
---|
ref | react ref or window , etc | null | The element the touchstart , touchmove , touchend , and mousedown event listeners are attached to. mousemove and mouseup are attached dynamically to the window in order to account for fast mouse movements that may cause the target element to lose focus. |
Argument 2
Property | type | Default | Description |
---|
onStart | function | (state, event) => {} | Callback function executed on the start phase of the touch or mouse event. |
onMove | function | (state, event) => {} | Callback function executed on the move phase of the touch or mouse event. |
onEnd | function | (state, event) => {} | Callback function executed on the end phase of the touch or mouse event. |
onInteraction | function | (state, event) => {} | Callback function executed on the start ,move , and end phase of the touch or mouse event. |
touch | boolean | true | Enables touch event listeners on the element. |
mouse | boolean | true | Enables mouse event listeners on the element. |
imperative | boolean | false | Prevents re-renders during the phases of the interaction events. This ideal for use with the callbacks when using an animation library that acts directly on the DOM element. |
capture | boolean | false | Boolean for altering the order of the handler's invocation. Click here for more info. |
once | boolean | false | Boolean indicating that the listener should be called only once and then be removed. |
passive | boolean | false | Boolean indicating whether or not to create a passive listener (which stops preventDefault from being called). |
preventContextMenu | boolean | false | Boolean indicating whether to preventDefault if the target element ever triggers a context menu event. While the use case for this is very much dependent on the css of the target element, setting this to true is recommended if mouse events are used. The contextmenu event can be triggered accidently from all sorts of user interactions with the target element while using a mouse, therefore canceling the mouseup event and causing the mousemove event to run indefintely. |
State
Property | type | Default | Description |
---|
active | boolean | false | Whether a touch or mouse event is active or not. |
identifier | integer | null | Used to identify the touch. This is used in a multi touch package. |
phase | string | null | Describes the current phase of the touch or mouse event. The phase can be start , move , or end . |
client | object | { x:0, y:0 } | The x and y coordinates of the event relative to the viewport, not including the scroll offset. |
screen | object | { x:0, y:0 } | The x and y coordinates of the event relative to the screen, not including any scroll offset. |
page | object | { x:0, y:0 } | The x and y coordinates of the event relative to the screen, including the scroll offset. |
start | object | { x:0, y:0, time:null } | Includes the page x and y coordinates, and the time in milliseconds during the start phase of the interaction event. |
move | object | { x:0, y:0,
continued:{ x:0, y:0, } } | Includes the page x and y coordinates, during the move phase of the interaction event. The move.continued object provides a continuation of the x and y coordinates between events. |
end | object | { x:0, y:0, time:null } | Includes the page x and y coordinates, and the time in milliseconds during the end phase of the interaction event. |
direction | string | none | Provides the current direction of the interaction event from the original starting coordinate. The possibilities are:
up ,
upleft ,
up_right ,
left ,
right ,
down ,
down_left ,
down_right ,
none |
distance | object | { x:0, y:0,
total:null } | The current x and y distances traveled from start to move.The total includes the total distance traveled. |
velocity | object | { x:0, y:0 } | The current x and y velocity of the mouse or touch event. |
time | date | null | The on going time of the event. |
duration | object | {
milliseconds:0, seconds:0 } | The duration of the event in milliseconds and formatted in seconds. |