Skip to content

Add useMove hook to @react-aria/interactions #1018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
devongovett opened this issue Aug 25, 2020 · 1 comment · Fixed by #1106
Closed

Add useMove hook to @react-aria/interactions #1018

devongovett opened this issue Aug 25, 2020 · 1 comment · Fixed by #1106
Assignees
Labels
enhancement New feature or request rsp:Slider

Comments

@devongovett
Copy link
Member

🙋 Feature Request

useMove will be a new interaction hook that allows the user to move an object's position on screen, both by dragging with a mouse or touch, and by using the arrow keys on the keyboard. This can be used to implement components like sliders, split views, color areas, and more.

We already have the useDrag1D hook in @react-aria/utils, however it currently does not support touch, and only supports dragging in one direction at a time (via an orientation option). For things like color area, color wheel, and dials (circular sliders), we'll need 2d movement support. The idea will be to deprecate useDrag1D and use useMove for all of these.

💁 Possible Solution

The first step will be to copy useDrag1D into @react-aria/interactions, rename to useMove, and simplify the API to match other interaction hooks. The old implementation will need to stay to prevent breaking changes, but we can deprecate it.

interface MoveEvent {
  type: 'movestart' | 'move' | 'moveend',
  pointerType: 'mouse' | 'pen' | 'touch' | 'keyboard',
  deltaX: number,
  deltaY: number
}

interface MoveProps {
  onMoveStart: (e: MoveEvent) => void,
  onMove?: (e: MoveEvent) => void,
  onMoveEnd?: (e: MoveEvent) => void
}

This is quite a few less props than useDrag1D currently accepts, so what are the replacements?

  • containerRef - removed. Move events just tell us the delta to move by, not an absolute position from a container.
  • reverse - removed. We will automatically flip the offsets in RTL depending on the direction returned from useLocale.
  • orientation - removed. Move events will support both x and y positions.
  • onHover - removed. Use the useHover hook.
  • onDrag - replaced with onMoveStart and onMoveEnd events.
  • onPositionChange - replaced with onMove. Note that the position is replaced by deltaX and deltaY properties which indicate the amount the the position has changed on each axis since the last event.
  • onIncrement/onDecrement - fires onMove with either deltaX or deltaY set to 1 or -1 depending on which directional arrow key was pressed.
  • onIncrementToMax/onDecrementToMin - removed. Won't be possible to know which axis to move to the min or max. Home/End can be handled in individual components.
  • onCollapseToggle - removed. Should be handled in individual components.

Behavior

  • Fire onMoveStart when the user presses down with their pointer and moves by at least 1px. Also fired on key down of an arrow key prior to onMove.
  • Fire onMove for each pointer move event, with a delta since the last point. Also fired repeatedly while the user holds down an arrow key (onKeyDown should already handle this).
  • Fire onMoveEnd on pointer up, and also on key up.

Touch events

The current implementation of useDrag1D does not handle touch events. We should implement this on top of pointer events where available, and then fall back to touch/mouse events when not available, just like other interaction hooks. In addition to the obvious events, we'll also need to handle onPointerCancel/onTouchCancel to ensure that we reset the dragging state when touches are canceled by the system.

🧢 Your Company/Team

RSP

@mischnic
Copy link
Contributor

when the user presses down with their pointer and moves by at least 1px

Merely pressing down should focus an underlying hidden <input> element (even without moving):

  const focusInput = useCallback(() => {
    if (inputRef.current) {
      focusWithoutScrolling(inputRef.current);
    }
  }, [inputRef]);

  return mergeProps(..., {
    onMouseDown: focusInput
  });

So we need something like onPressStart?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request rsp:Slider
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants