Glazzes / react-native-zoom-toolkit

Zoom anything you want! Most complete pinch to zoom utilities for React Native
https://glazzes.github.io/react-native-zoom-toolkit/
MIT License
186 stars 11 forks source link

[Feature]: Export hooks for usage in other components (eg. Skia) #51

Closed erandagan closed 2 months ago

erandagan commented 2 months ago

Summary

Great work on this. It'd be super helpful if the library would also expose its lower level APIs (useXCommons) for integration in custom components (like Skia elements) which need to be made interactive.

As the README states:

The most feature rich React Native library to solve common use cases of the pinch to zoom interaction, as well as providing barebones utilities for complex use cases, such as pinch to zoom React Native Skia's components.

Expected API

import { usePanCommons, usePinchCommons } from "react-native-zoom-toolkit

Another option is to export the high-level API in the form of hooks which return transformation matrices, which can be then applied to RN views, Skia views, or further extended in other ways.

const { gesture: panGesture, matrix } = usePanGesture(...);
const { gesture: pinchGesture, matrix } = usePinchGesture(...);
Glazzes commented 2 months ago

Hi there, as the README states yes you can use them with Skia with some extra work from the user as demostrated in the Example App while using CropZoom with Skia, anyway I've been thinking of expanding the primitives for this use case, so let me address some concers first.

useXCommons

These APIS are meant to recycle as much code as possible, they're 100% unsuable for a user of the library as it requires the creation of several shared values, calculate stuff like max scale yourself and many more.

Even if you wanted to pretty much rewrite any of the components yourself, setting the functions of these APIS to a Gesture is not as easy as setting it to a GestureDetector and then you're done, so they are out of the table.

Exposing gestures

Although its possible it requires much more effort than it meets the eye, not only for me but for the end user aswell in order to make them functional, I have also made use of some nonesenses ("tricks") that would need to be reimplemented by the end user, this leading to a poor dx.

Possible solution?

All components but Gallery come with onGestureActive callback which reports the changes on their transformation values, so it would be easier to work around that and provide a boilerplate for these use cases, kinda like this one:

import {
  useDerivedValue,
  useSharedValue,
  type SharedValue,
} from 'react-native-reanimated';
import type { ResumableZoomState } from '../components/resumable/types';

type ResumableValues = {
  onUpdate: (state: ResumableZoomState) => void;
  matrix: Readonly<SharedValue<number[]>>;
};

export const useResumableValues = (): ResumableValues => {
  const translateX = useSharedValue<number>(0);
  const translateY = useSharedValue<number>(0);
  const scale = useSharedValue<number>(1);

  const matrix = useDerivedValue<number[]>(() => {
    return [
      scale.value,
      0,
      0,
      0,
      0,
      scale.value,
      0,
      0,
      0,
      0,
      1,
      0,
      translateX.value,
      translateY.value,
      0,
      1,
    ];
  }, [scale, translateX, translateY]);

  const onUpdate = (state: ResumableZoomState) => {
    'worklet';
    translateX.value = state.translateX;
    translateY.value = state.translateY;
    scale.value = state.scale;
  };

  return { onUpdate, matrix };
};

With an expected usage like this one:

const { onUpdate, matrix } = useResumableValues();

// onGestureActive will be renamed to onUpdate in the next major release
<ResumableZoom onGestureActive={onUpdate}>
  <SomeTransparentView />
</ResumableZoom>

....
// Somewhere in Skia
<Canvas>
  <Group matrix={matrix}>
    <Image {...props} />
  </Group>
</Canvas>

Due to the small complexity of its usage I think an entry in docs as an usage guide would help for a better understanding of its usage, like "How to use with Skia Components".

Let me know your thoughts.

Glazzes commented 2 months ago

I've writen a new guide in docs for the intended usage of both libraries together How to use with Skia Components, this is temporary but I think it will serve well, I've decided what I commented will be the expected API to deal with this issue.

Glazzes commented 2 months ago

Just released version 3.0.0 including the new useTransformationState hook, I decided to use a transform based approach rather than a matrix approach because RN and RN Skia use different matrix conventions, RN uses row major syntax and Skia column major syntax, what looks fine on one will look completely distorted in the other.