Skip to content

enzomanuelmangano/react-native-inkwell

Repository files navigation

👉🏼 React Native InkWell

A material touchable area that provides the ripple effect. Inspired by the InkWell Flutter component.

Installation

You need to have already installed the following packages:

Open a Terminal in your project's folder and install the library using yarn:

yarn add react-native-inkwell

or with npm:

npm install react-native-inkwell

Usage

import InkWell from 'react-native-inkwell';

const YourRippleButton = () => (
  <InkWell
    style={{
      width: 200,
      height: 200,
      backgroundColor: 'white',
    }}
    contentContainerStyle={{
      alignItems: 'center',
      justifyContent: 'center',
    }}
    onTap={() => {
      console.log('tapped');
    }}
  >
    <Text>Tap Here</Text>
  </InkWell>
);

Properties

enabled?: boolean

Indicates whether InkWell should be active or not.

Default: true.


radius?: number

Decides the maximum radius of the Ripple Effect. By default the Ripple effect will determine the radius from the height and width of the component so that it can expand as much as possible.


onTap?: () => void

Called when the InkWell is clicked. If the onDoubleTap callback is not specified, onTap will be called immediately, otherwise it will be called after maxDelayMs.


onTapDown?: () => void

Called when the user taps down the InkWell.


onTapCancel?: () => void

Called when the user cancels a tap.


onDoubleTap?: () => void

Called when the InkWell is clicked two consecutive times in less than maxDelayMs.


onLongPress?: () => void

Called when the component is pressed for more than minDurationMs.


maxDelayMs?: number

Maximum time, expressed in milliseconds, that can pass before the next tap — if many taps are required.

This property is inherited from maxDelayMs of the react-native-gesture-handler's TapGestureHandler.

Default: 500


minDurationMs?: number

Minimum time, expressed in milliseconds, that a finger must remain pressed on the corresponding view.

This property is inherited from minDurationMs of the react-native-gesture-handler's LongPressGestureHandler.

Default: 500


scaleDuration?: number

The duration of ink scale animation.

Default: depends on the component's width and height.


easing?: Animated.WithTimingConfig["easing"]

The Reanimated EasingFunction.

Default: Easing.bezier(0.25, 0.5, 0.4, 1.0)


splashColor?: string

The splash color of the ripple effect.

Default: rgba(0,0,0,0.1);


highlightColor?: string

The backgroundColor of the View when the InkWell is activated.

Default: rgba(0,0,0,0.03);


style?: StyleProp<ViewStyle>

A React Native style.


contentContainerStyle?: StyleProp<ViewStyle>

The React Native style of the content.


children?: React.ReactNode

The component that could be contained in the InkWell.


simultaneousHandlers and waitFor

Inherited from react-native-gesture-handler in order to support Cross Handler Interactions if needed.


Hooks

useInkWellRef

Under the hood this hook is using useAnimatedRef from react-native-reanimated. When provided, it is used by the InkWell in order to measure the layout on the UI Thread.


Nested InkWells

Since the InkWell is built on top of the react-native-gesture-handler component TapGestureHandler, by default, upon clicking an InkWell inside another, the tap will be propagated to the parent as well.

Fortunately, this case study is easily handled. First, a Ref must be created and assigned to the InkWell that is being nested. Once this is done, the Ref must be added to the childrenRefs property of the InkWell. That's it.

const NestedInkWellUseCase = () => {
  const onTapParent = React.useCallback(() => {
    console.log('Parent');
  }, []);

  const onTapChild = React.useCallback(() => {
    console.log('Child');
  }, []);

  // 1. create the refs
  const firstChildRef = useInkWellRef();
  const secondChildRef = useInkWellRef();

  return (
    <View style={styles.buttonContainer}>
      {/* Parent */}
      <InkWell
        style={styles.button}
        contentContainerStyle={styles.contentButton}
        onTap={onTapParent}
        childrenRefs={[firstChildRef, secondChildRef]} // <-- 4. add the childRef to the childrenRefs
      >
        {/* First nested InkWell */}
        <InkWell
          ref={firstChildRef} // <--  2. assign the firstChildRef
          style={[styles.button, styles.innerButton]}
          contentContainerStyle={styles.contentButton}
          onTap={onTapChild}
        >
          <Text>Child</Text>
        </InkWell>
        {/* Second nested InkWell */}
        <InkWell
          ref={secondChildRef} // <--  3. assign the secondChildRef
          style={[styles.button, styles.innerButton]}
          contentContainerStyle={styles.contentButton}
          onTap={onTapChild}
        >
          <Text>Child</Text>
        </InkWell>
      </InkWell>
    </View>
  );
};

Here's the result:


Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

MIT