Hone logo
Hone
Problems

React usePointer Hook: Capturing Pointer Events

This challenge asks you to create a custom React hook, usePointer, that provides a clean and reusable way to track pointer (mouse, touch, pen) events within a React component. This hook will manage the pointer's state (down, up, move, leave) and provide callbacks for each event, simplifying the handling of complex pointer interactions. It's a useful tool for building interactive components like drag-and-drop interfaces, custom controls, or any UI element that responds to pointer input.

Problem Description

You need to implement the usePointer hook in TypeScript. This hook should:

  1. Accept a Callback Function: The hook should accept a single argument: a callback function onPointerStateChange. This function will be called whenever the pointer state changes (e.g., from "idle" to "down", from "down" to "up"). The callback will receive an object with the following properties:

    • state: A string representing the current pointer state. Possible values are: "idle", "down", "move", "up", "leave".
    • pointerEvent: The original PointerEvent object.
  2. Manage Pointer State: The hook should internally manage the pointer's state and update it based on pointer events.

  3. Attach Event Listeners: The hook should attach the necessary event listeners to the document to capture pointer events. These listeners should be:

    • pointerdown: Sets the state to "down" and calls onPointerStateChange.
    • pointermove: Sets the state to "move" and calls onPointerStateChange.
    • pointerup: Sets the state to "up" and calls onPointerStateChange.
    • pointerleave: Sets the state to "leave" and calls onPointerStateChange.
    • pointercancel: Sets the state to "up" and calls onPointerStateChange. (Handles cases where the pointer event is cancelled, e.g., by a browser gesture).
  4. Cleanup: The hook should clean up the event listeners when the component unmounts to prevent memory leaks.

  5. Return Value: The hook should return undefined. The primary purpose is to manage the event listeners and state changes.

Expected Behavior:

  • When a pointer button is pressed down (pointerdown), the state should change to "down", and the callback should be invoked.
  • While the pointer is down and moving (pointermove), the state should change to "move", and the callback should be invoked.
  • When the pointer button is released (pointerup), the state should change to "up", and the callback should be invoked.
  • When the pointer leaves the element (pointerleave), the state should change to "leave", and the callback should be invoked.
  • When the pointer event is cancelled (pointercancel), the state should change to "up", and the callback should be invoked.
  • When no pointer interaction is occurring, the state should be "idle".

Examples

Example 1:

Input: A React component using the usePointer hook with a console.log callback.
Output: Console logs indicating state changes as the mouse pointer is pressed, moved, released, and leaves the window.
Explanation: The hook correctly captures pointer events and updates the state, triggering the callback with the appropriate state and event data.

Example 2:

Input: A React component using the usePointer hook with a callback that updates a state variable to track the pointer's current state.
Output: The component's state variable accurately reflects the current pointer state (idle, down, move, up, leave).
Explanation: The hook's callback correctly provides the state information, allowing the component to react to pointer events.

Example 3: (Edge Case - Pointer Cancel)

Input: A React component using the usePointer hook. The user starts a drag gesture, but the browser cancels it (e.g., due to a system gesture).
Output: The console log (if used as a callback) shows a "up" state change, and the component reacts as if the pointer was released.
Explanation: The `pointercancel` event is correctly handled, ensuring a consistent user experience.

Constraints

  • The hook must be written in TypeScript.
  • The hook must attach event listeners to the document object.
  • The hook must clean up the event listeners when the component unmounts.
  • The onPointerStateChange callback must be called with the correct state and the original PointerEvent object.
  • The hook should not introduce any unnecessary dependencies.

Notes

  • Consider using useEffect to manage the event listeners and cleanup.
  • The PointerEvent object contains valuable information about the pointer, such as its position, pressure, and button state. While the problem doesn't require you to use this information, it's good to be aware of it.
  • Think about how to handle the initial state of the pointer (it should be "idle").
  • The pointercancel event is important for handling situations where the pointer event is cancelled by the browser. Failing to handle this can lead to unexpected behavior.
Loading editor...
typescript