Skip to content
horizontal, swipeable gesture views for react
Branch: master
Clone or download
Latest commit 57373ab May 17, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.storybook initial commit May 5, 2019
src add auto focus option May 17, 2019
stories add auto focus option May 17, 2019
.gitignore update gitignore May 6, 2019
.npmignore initial commit May 5, 2019
Readme.md update readme with better embedded views options and new props May 10, 2019
babel.config.js initial commit May 5, 2019
demo.gif add gif May 7, 2019
jest.config.js initial commit May 5, 2019
package.json 2.0.0 May 17, 2019
rollup.config.js initial commit May 5, 2019
tsconfig.json initial commit May 5, 2019
yarn.lock add basic functioning grid May 11, 2019

Readme.md

A demo showing views being swiped left and right.

react-gesture-view

npm package Follow on Twitter

React-gesture-view is a react library for providing views that can be swiped left or right. It was originally built for use in Sancho UI.

Features

  • Built with react-gesture-responder to enable better control over gesture delegation. This means that you can embed gesture based controls within this gesture view (or embed multiple gesture views within eachother) and delegate between them.
  • Configurable. Configure the animation spring, enable mouse support, use child render callbacks, etc.
  • Optional lazy loading.

Install

Install react-gesture-view and its peer dependency react-gesture-responder using yarn or npm.

yarn add react-gesture-view react-gesture-responder

Basic usage

The gesture view should be provided with a collection of children, each representing a panel. By default, each child will be wrapped in an element wiith the recommended props. If you'd rather render the element yourself, provide a render callback for each child instead.

import GestureView from "react-gesture-view";

function TabContent() {
  const [index, setIndex] = React.useState(0);
  return (
    <GestureView value={index} onRequestChange={i => setIndex(i)}>
      <div>First panel</div>
      <div>Second panel</div>
      <div>Third panel</div>
      {(props, active, load) => <div {...props}>fourth panel</div>}
    </GestureView>
  );
}

API

Name Type Default Value Description
value* number The current index to show
onRequestChange* (value: number) => void; A callback for handling index changes
lazyLoad boolean false Lazy load pane contents
enableMouse boolean false By default mouse gestures are not enabled
enableGestures boolean true By default gestures are enabled
animationConfig SpringConfig { tension: 190, friction: 20, mass: 0.4 } A react-spring config for animations
onTerminationRequest (state) => boolean; Optionally prevent parent views from claiming the pan-responder. Useful for embedded gesture views
onMoveShouldSet (state, e, suggested) => boolean; Optionally override the default onMoveShouldSet behaviour. Useful for embedding multiple gesture views.
enableScrollLock boolean true Lock all page scrolling when making swiping gestures. This is generally the desired behaviour.

Imperative API

You can use the imperative API to manually focus the active panel, which is something you'll likely want to do for accessibility reasons.

function TabContent() {
  const [index, setIndex] = React.useState(0);
  const ref = React.useRef();

  function focusCurrentIndex() {
    ref.current.focus();
  }

  return (
    <GestureView ref={ref} value={index} onRequestChange={i => setIndex(i)}>
      <div>First panel</div>
      <div>Second panel</div>
      <div>Third panel</div>
    </GestureView>
  );
}

Embedding Views

Each GestureView exposes the react-gesture-responder onTerminationRequest function which allows you to negotiate between gesture views competing for the responder. Typically, you'll want the child view to prevent the parent from claiming the responder.

<GestureView>
  <div>Left parent pane</div>
  <GestureView onTerminationRequest={() => false}>
    <div>child pane</div>
    <div>another child</div>
  </GestureView>
</GestureView>

The logic can become more sophisticated. In the gif at the top of the readme, our parent claims the responder (and prevents the child from stealing it) when showing the first child pane and moving left. The code will look something like this:

const [childIndex, setChildIndex] = React.useState(0);
const [parentIndex, setParentIndex] = React.useState(0);

function onMoveShouldSet(state, e, suggested) {
  if (suggested) {
    if (parentIndex === 0 || (state.delta[0] > 0 && childIndex === 0)) {
      return true;
    }
  }

  return false;
}

function onTerminationRequest(state) {
  if (state.delta[0] > 0 && childIndex === 0) {
    return false;
  }

  return true;
}

<GestureView
  onMoveShouldSet={onMoveShouldSet}
  onTerminationRequest={onTerminationRequest}
  value={parentIndex}
  onRequestChange={i => setParentIndex(i)}
>
  <div>Left parent pane</div>
  <GestureView value={childIndex} onRequestChange={i => setChildIndex(i)}>
    <div>child pane</div>
    <div>another child</div>
  </GestureView>
</GestureView>;
You can’t perform that action at this time.