Conversation
…ied pinch gesture boundary check
nd versioned docs to also not rely on the SrcFiles
There was a problem hiding this comment.
Pull request overview
Updates the docs site examples and dependencies for docs-gesture-handler, aligning interactive gesture examples with the newer docs structure and updated runtime packages.
Changes:
- Update docs pages to load examples from new locations (and remove embedded preview videos).
- Add/refresh versioned
2.xexample implementations underversioned_docs. - Bump the docs site’s React Native ecosystem deps (RNGH, Reanimated, RN Web, Worklets) and adjust the Babel plugin accordingly.
Reviewed changes
Copilot reviewed 36 out of 37 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/docs-gesture-handler/yarn.lock | Dependency lock updates after package bumps. |
| packages/docs-gesture-handler/package.json | Bumps docs-site deps (RNGH, Reanimated, RN Web, Worklets). |
| packages/docs-gesture-handler/babel.config.js | Switches Babel plugin to react-native-worklets/plugin. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/gestures/tap-gesture.md | Points 2.x doc page to versioned example imports; removes video blocks. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/gestures/rotation-gesture.md | Same: versioned example imports; removes video blocks. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/gestures/pinch-gesture.md | Same: versioned example imports; removes video blocks. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/gestures/pan-gesture.md | Same: versioned example imports; removes video blocks. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/gestures/long-press-gesture.md | Same: versioned example imports; removes video blocks. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/gestures/hover-gesture.md | Same: versioned example imports; removes video blocks. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/gestures/fling-gesture.md | Same: versioned example imports; removes video blocks. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/examples/TapGestureBasic.js | Adds a versioned 2.x tap example. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/examples/RotationGestureBasic.js | Adds a versioned 2.x rotation example. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/examples/PinchGestureBasic.js | Adds a versioned 2.x pinch example. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/examples/PanGestureBasic.js | Updates versioned 2.x pan example sizing/measurement. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/examples/LongPressGestureBasic.js | Adds a versioned 2.x long-press example. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/examples/HoverGestureBasic.js | Adds a versioned 2.x hover example. |
| packages/docs-gesture-handler/versioned_docs/version-2.x/examples/FlingGestureBasic.js | Updates versioned 2.x fling example sizing/measurement. |
| packages/docs-gesture-handler/static/examples/TapGestureBasic.js | Migrates static tap example to useTapGesture. |
| packages/docs-gesture-handler/static/examples/RotationGestureBasic.js | Migrates static rotation example to usePanGesture. |
| packages/docs-gesture-handler/static/examples/RotationGestureBasicSrc.js | Removes old *Src file (raw-loader now targets main example). |
| packages/docs-gesture-handler/static/examples/PinchGestureBasic.js | Migrates static pinch example to usePanGesture and new measurement logic. |
| packages/docs-gesture-handler/static/examples/PinchGestureBasicSrc.js | Removes old *Src file (raw-loader now targets main example). |
| packages/docs-gesture-handler/static/examples/PanGestureBasic.js | Migrates static pan example to usePanGesture and new measurement logic. |
| packages/docs-gesture-handler/static/examples/LongPressGestureBasic.js | Migrates static long-press example to useLongPressGesture. |
| packages/docs-gesture-handler/static/examples/HoverGestureBasic.js | Migrates static hover example to useHoverGesture. |
| packages/docs-gesture-handler/static/examples/FlingGestureBasic.js | Migrates static fling example to useFlingGesture. |
| packages/docs-gesture-handler/docs/legacy-gestures/rotation-gesture.md | Updates raw-loader import to point at main example file. |
| packages/docs-gesture-handler/docs/legacy-gestures/pinch-gesture.md | Updates raw-loader import to point at main example file. |
| packages/docs-gesture-handler/docs/legacy-gestures/pan-gesture.md | Updates raw-loader import to point at main example file. |
| packages/docs-gesture-handler/docs/legacy-gestures/fling-gesture.md | Updates raw-loader import to point at main example file. |
| packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx | Removes embedded preview video blocks. |
| packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx | Updates raw-loader import + removes embedded preview video blocks. |
| packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx | Updates raw-loader import + removes embedded preview video blocks. |
| packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx | Updates raw-loader import + removes embedded preview video blocks. |
| packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx | Removes embedded preview video blocks. |
| packages/docs-gesture-handler/docs/gestures/use-hover-gesture.mdx | Removes embedded preview video blocks. |
| packages/docs-gesture-handler/docs/gestures/use-fling-gesture.mdx | Updates raw-loader import + removes embedded preview video blocks. |
Comments suppressed due to low confidence (6)
packages/docs-gesture-handler/versioned_docs/version-2.x/examples/PanGestureBasic.js:84
GestureHandlerRootViewdoesn’t forward refs, soref={containerRef}will be ignored andmeasureInWindowwon’t updatemaxTranslateX/Y. This will keep the clamp bounds at 0 and prevent dragging. Put the ref on an innerViewwrapper instead.
packages/docs-gesture-handler/versioned_docs/version-2.x/examples/PanGestureBasic.js:71clampis called inside.onUpdate, which runs as a worklet when using the Reanimated-integratedGestureAPI. A plain JS helper can cause runtime failures when called from a worklet. Add a'worklet'directive toclampor inline the clamp logic in the callback.
packages/docs-gesture-handler/versioned_docs/version-2.x/examples/PanGestureBasic.js:76- Same worklet concern for Y translation:
clampis invoked in the worklet.onUpdatecallback. Ensureclampis worklet-safe to avoid runtime errors.
packages/docs-gesture-handler/versioned_docs/version-2.x/examples/PanGestureBasic.js:42 maxTranslateYis set toheight / 2, which lets the 100px-tall box translate beyond the container’s vertical bounds. To keep it fully visible, subtract half the box size (similar to the X calculation).
packages/docs-gesture-handler/static/examples/PanGestureBasic.js:71onUpdatecallbacks created byusePanGesturerun as worklets; calling a plain JS helper likeclampfrom inside them can throw at runtime (“tried to call a non-worklet function”). Markclampas a worklet (add a'worklet'directive) or inline the min/max logic inside the callbacks.
onUpdate: (event) => {
translationX.value = clamp(
prevTranslationX.value + event.translationX,
-maxTranslateX.value,
maxTranslateX.value
);
packages/docs-gesture-handler/versioned_docs/version-2.x/examples/FlingGestureBasic.js:63
clampis called inside the worklet.onStartcallback (Reanimated-integratedGestureAPI). Ifclampisn’t workletized, this can throw at runtime. Add a'worklet'directive toclampor inline the clamp logic.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <GestureHandlerRootView ref={containerRef} style={[styles.container, { height: maxBoxSize.value }]}> | ||
| <GestureDetector gesture={pan}> | ||
| <Animated.View | ||
| ref={boxRef} | ||
| style={[styles.box, boxAnimatedStyles]}></Animated.View> | ||
| </GestureDetector> | ||
| <Animated.View | ||
| style={[ | ||
| styles.dot, | ||
| { | ||
| transform: [ | ||
| { translateX: pointerPositionX }, | ||
| { translateY: pointerPositionY }, | ||
| ], | ||
| opacity: touchOpacity, | ||
| }, | ||
| ]}></Animated.View> | ||
| <Animated.View | ||
| style={[ | ||
| styles.dot, | ||
| { | ||
| transform: [ | ||
| { translateX: negativePointerPositionX }, | ||
| { translateY: negativePointerPositionY }, | ||
| ], | ||
| opacity: touchOpacity, | ||
| }, | ||
| ]}></Animated.View> |
There was a problem hiding this comment.
GestureHandlerRootView does not forward refs, so ref={containerRef} won’t attach and measureInWindow won’t update maxBoxSize. This can break clamping/initial sizing. Attach the ref to an inner View wrapper inside the root view instead.
| <GestureHandlerRootView ref={containerRef} style={[styles.container, { height: maxBoxSize.value }]}> | |
| <GestureDetector gesture={pan}> | |
| <Animated.View | |
| ref={boxRef} | |
| style={[styles.box, boxAnimatedStyles]}></Animated.View> | |
| </GestureDetector> | |
| <Animated.View | |
| style={[ | |
| styles.dot, | |
| { | |
| transform: [ | |
| { translateX: pointerPositionX }, | |
| { translateY: pointerPositionY }, | |
| ], | |
| opacity: touchOpacity, | |
| }, | |
| ]}></Animated.View> | |
| <Animated.View | |
| style={[ | |
| styles.dot, | |
| { | |
| transform: [ | |
| { translateX: negativePointerPositionX }, | |
| { translateY: negativePointerPositionY }, | |
| ], | |
| opacity: touchOpacity, | |
| }, | |
| ]}></Animated.View> | |
| <GestureHandlerRootView style={styles.container}> | |
| <View ref={containerRef} style={[styles.container, { height: maxBoxSize.value }]}> | |
| <GestureDetector gesture={pan}> | |
| <Animated.View | |
| ref={boxRef} | |
| style={[styles.box, boxAnimatedStyles]}></Animated.View> | |
| </GestureDetector> | |
| <Animated.View | |
| style={[ | |
| styles.dot, | |
| { | |
| transform: [ | |
| { translateX: pointerPositionX }, | |
| { translateY: pointerPositionY }, | |
| ], | |
| opacity: touchOpacity, | |
| }, | |
| ]}></Animated.View> | |
| <Animated.View | |
| style={[ | |
| styles.dot, | |
| { | |
| transform: [ | |
| { translateX: negativePointerPositionX }, | |
| { translateY: negativePointerPositionY }, | |
| ], | |
| opacity: touchOpacity, | |
| }, | |
| ]}></Animated.View> | |
| </View> |
| containerRef.current.measureInWindow((x, y, width, height) => { | ||
| maxTranslateX.value = width / 2 - 50; | ||
| maxTranslateY.value = height / 2 - 50; | ||
| maxTranslateY.value = height / 2; |
There was a problem hiding this comment.
maxTranslateY is calculated as height / 2, but the clamp bounds should typically subtract half the box size (like X does with - 50) to keep the 100x100 box fully within the container. Otherwise the box can move partially out of view vertically.
| maxTranslateY.value = height / 2; | |
| maxTranslateY.value = height / 2 - 50; |
| onUpdate: (event) => { | ||
| const distanceX = Math.abs(event.absoluteX - centerX.value); | ||
| const distanceY = Math.abs(event.absoluteY - centerY.value); | ||
| boxWidth.value = clamp( | ||
| Math.max(distanceX, distanceY) * 2 + distanceDifference.value, | ||
| 100, | ||
| Math.min(width.value, height.value) | ||
| minBoxSize, | ||
| maxBoxSize.value | ||
| ); |
There was a problem hiding this comment.
clamp is invoked from within usePanGesture worklet callbacks. As written, clamp is a plain JS function, which can cause runtime errors when called from a worklet. Make clamp a worklet (add 'worklet') or inline the clamp logic in the callback.
| <GestureHandlerRootView ref={containerRef} style={styles.container}> | ||
| <GestureDetector gesture={pan}> | ||
| <Animated.View style={[animatedStyles, styles.box]}></Animated.View> | ||
| </GestureDetector> |
There was a problem hiding this comment.
GestureHandlerRootView is a function component and doesn’t forward refs, so ref={containerRef} won’t attach to the underlying native View. As a result measureInWindow won’t run and maxTranslate values will stay 0 (drag will appear “stuck”). Wrap the contents in a plain View (or Animated.View) inside GestureHandlerRootView and put the ref on that wrapper instead.
| <GestureHandlerRootView ref={containerRef} style={styles.container}> | |
| <GestureDetector gesture={pan}> | |
| <Animated.View style={[animatedStyles, styles.box]}></Animated.View> | |
| </GestureDetector> | |
| <GestureHandlerRootView style={styles.container}> | |
| <View ref={containerRef} style={styles.container}> | |
| <GestureDetector gesture={pan}> | |
| <Animated.View style={[animatedStyles, styles.box]}></Animated.View> | |
| </GestureDetector> | |
| </View> |
| <GestureHandlerRootView ref={containerRef} style={styles.container}> | ||
| <GestureDetector gesture={pan}> | ||
| <Animated.View |
There was a problem hiding this comment.
GestureHandlerRootView doesn’t forward refs, so ref={containerRef} won’t attach and measureInWindow won’t update maxBoxSize (which then breaks clamping). Put the ref on a child View wrapper inside the root view instead.
| .onUpdate((event) => { | ||
| const distanceX = Math.abs(event.absoluteX - centerX.value); | ||
| const distanceY = Math.abs(event.absoluteY - centerY.value); | ||
| boxWidth.value = clamp( | ||
| Math.max(distanceX, distanceY) * 2 + distanceDifference.value, | ||
| minBoxSize, | ||
| maxBoxSize.value | ||
| ); |
There was a problem hiding this comment.
clamp is used inside .onUpdate, which runs as a worklet with the Reanimated-integrated Gesture API. A plain JS helper can’t be called from a worklet and may throw at runtime. Add 'worklet' to clamp or inline the clamp math.
| translationY.value = clamp( | ||
| prevTranslationY.value + event.translationY, | ||
| -maxTranslateY.value, | ||
| maxTranslateY.value | ||
| ); |
There was a problem hiding this comment.
Same worklet issue as above: clamp is called inside the worklet onUpdate callback for Y translation. Ensure clamp is worklet-safe (or inline it) to avoid runtime errors.
| @@ -63,7 +63,8 @@ export default function App() { | |||
| ), | |||
| { duration: 200 } | |||
There was a problem hiding this comment.
useFlingGesture callback functions run as worklets by default; calling the plain JS helper clamp inside onActivate can throw at runtime. Mark clamp with a 'worklet' directive (or inline the clamp) so it’s callable from the worklet.
| <Animated.View | ||
| style={[ | ||
| styles.dot, | ||
| { | ||
| transform: [ | ||
| { translateX: pointerPositionX }, | ||
| { translateY: pointerPositionY }, | ||
| ], | ||
| opacity: touchOpacity, | ||
| }, | ||
| ]}></Animated.View> | ||
| <Animated.View |
There was a problem hiding this comment.
The dot overlays are rendered after the box and positioned on top of it, so they can intercept pointer events and make the box hard/impossible to interact with (especially on web). Consider setting pointerEvents: 'none' on the dot views/styles so gestures go through to the target.
| <Animated.View | ||
| style={[ | ||
| styles.dot, | ||
| { | ||
| transform: [ | ||
| { translateX: pointerPositionX }, | ||
| { translateY: pointerPositionY }, | ||
| ], | ||
| opacity: touchOpacity, | ||
| }, | ||
| ]}></Animated.View> | ||
| <Animated.View |
There was a problem hiding this comment.
The dot overlays are rendered after the box and positioned over its center, so they can intercept pointer events and prevent interacting with the box (especially on web). Consider setting pointerEvents: 'none' on the dot views/styles.
…re-handler into @relextm19/docs-examples
Description
Updated docs examples for v2 and v3 api. Removed videos from docs.
Test plan
Manually tested changes