Skip to content

[apple] Handle hover in Touchable #4283

Open
m-bert wants to merge 14 commits into
mainfrom
@mbert/touchable-hover-ios
Open

[apple] Handle hover in Touchable #4283
m-bert wants to merge 14 commits into
mainfrom
@mbert/touchable-hover-ios

Conversation

@m-bert

@m-bert m-bert commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Description

Follow up for Android PR which brings hover animations to iOS, macOS and tvOS platforms.

Of course docs/jsdoc will have to be unified between them, it will be done after merging either of these.

Test plan

Tested on existing Touchable example and the code below:
import * as React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import {
  GestureHandlerRootView,
  Touchable as GHTouchable,
} from 'react-native-gesture-handler';

const SLOW = 700;

export default function App() {
  const [pressCount, setPressCount] = React.useState(0);
  const [disabled, setDisabled] = React.useState(false);

  // Auto-toggle `disabled` every 2s so hover mask/resume can be tested with a
  // mouse held still over the button — tapping a separate control would move
  // the pointer off first. Hover and watch: the visual masks to default while
  // disabled and resumes the hover look when re-enabled, pointer unmoved.
  React.useEffect(() => {
    const id = setInterval(() => setDisabled((d) => !d), 2000);
    return () => clearInterval(id);
  }, []);

  return (
    <GestureHandlerRootView style={styles.root}>
      <Text style={styles.title}>Slow hover + press</Text>
      <Text style={styles.hint}>
        Use a mouse / stylus. Hover to grow & fade, press to shrink & fade more.
        Transitions should never flicker through the default state.
      </Text>

      <View style={styles.stage}>
        <GHTouchable
          // Press (active) visuals
          defaultOpacity={1}
          defaultScale={1}
          activeOpacity={0.3}
          activeScale={0.8}
          // Hover visuals
          hoverOpacity={0.6}
          hoverScale={1.2}
          // Underlay so the change is extra visible
          underlayColor="black"
          defaultUnderlayOpacity={0}
          hoverUnderlayOpacity={0.15}
          activeUnderlayOpacity={0.35}
          // Slow everything down: in/out for both tap and hover
          animationDuration={{
            tap: { in: SLOW, out: SLOW },
            hover: { in: SLOW, out: SLOW },
          }}
          disabled={disabled}
          style={styles.button}
          onPress={() => setPressCount((c) => c + 1)}>
          <Text style={styles.buttonText}>Hover / Press me</Text>
        </GHTouchable>
      </View>

      <Text style={styles.counter}>
        {disabled ? 'DISABLED' : 'enabled'} · Presses: {pressCount}
      </Text>
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  root: {
    flex: 1,
    backgroundColor: '#ecf0f1',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 24,
  },
  title: {
    fontSize: 22,
    fontWeight: 'bold',
    color: '#2c3e50',
    marginBottom: 8,
  },
  hint: {
    fontSize: 14,
    color: '#7f8c8d',
    textAlign: 'center',
    marginBottom: 40,
  },
  stage: {
    width: 260,
    height: 260,
    alignItems: 'center',
    justifyContent: 'center',
  },
  button: {
    width: 180,
    height: 180,
    borderRadius: 24,
    backgroundColor: '#8e44ad',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 18,
    fontWeight: 'bold',
  },
  counter: {
    marginTop: 40,
    fontSize: 16,
    color: '#2c3e50',
    fontWeight: 'bold',
  },
});

Copilot AI review requested due to automatic review settings June 24, 2026 12:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds native hover-driven visual state support to the Touchable/RNGestureHandlerButton implementation on Apple platforms (iOS + macOS), aligning behavior with the existing web hover model and avoiding flicker during hover→press transitions.

Changes:

  • Extends the native button codegen spec with hover-related props (opacity/scale/underlay + hover in/out durations).
  • Implements hover tracking + animation orchestration in the Apple native button (iOS hover recognizer; macOS tracking area).
  • Updates public TS/JSDoc and docs to reflect hover availability (partial).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonNativeComponent.ts Adds hover-related native props to the shared codegen spec.
packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx Updates JSDoc platform notes for hover props.
packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm Wires new hover props from Fabric props into the native button view.
packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm Implements hover state tracking + hover/press animation coordination for iOS/macOS.
packages/react-native-gesture-handler/apple/RNGestureHandlerButton.h Exposes hover properties/durations on the native button.
packages/docs-gesture-handler/docs/components/touchable.mdx Updates docs to mention hover on iOS (and hover timing text).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx Outdated
Comment thread packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx Outdated
Comment thread packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx Outdated
Comment thread packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx Outdated
Comment thread packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx Outdated
Comment thread packages/docs-gesture-handler/docs/components/touchable.mdx Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

@m-bert m-bert requested a review from j-piasecki June 24, 2026 13:18
Comment thread packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm Outdated
Comment thread packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm Outdated
m-bert and others added 5 commits June 29, 2026 08:40
## Description

This PR removes obsolete version checks from our `iOS` codebase.

Minimal targets for iOS and macOS were chosen based on supported
versions. tvOS was changed to match iOS

## Test plan

Checked that example apps (basic and macos) are built correctly,
…ion/react-native-gesture-handler into @mbert/touchable-hover-ios
@m-bert m-bert requested a review from j-piasecki June 29, 2026 11:22
@m-bert m-bert changed the title [iOS | macOS] Handle hover in Touchable [apple] Handle hover in Touchable Jun 29, 2026
Comment thread packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm Outdated
Comment thread packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm Outdated
Comment thread packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm Outdated
Comment thread packages/react-native-gesture-handler/apple/RNGestureHandlerButton.mm Outdated
@m-bert

m-bert commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator Author

I've also trimmed comments, following android PR.

@m-bert m-bert requested a review from j-piasecki July 1, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants