react-native-skia-gesture 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +71 -20
  2. package/lib/commonjs/canvas/canvas.js +57 -56
  3. package/lib/commonjs/canvas/canvas.js.map +1 -1
  4. package/lib/commonjs/canvas/context.js +1 -1
  5. package/lib/commonjs/canvas/context.js.map +1 -1
  6. package/lib/commonjs/components/index.js +4 -4
  7. package/lib/commonjs/components/index.js.map +1 -1
  8. package/lib/commonjs/hoc/with-touchable-handler.js +29 -34
  9. package/lib/commonjs/hoc/with-touchable-handler.js.map +1 -1
  10. package/lib/commonjs/hooks/use-gesture-handler.js +11 -5
  11. package/lib/commonjs/hooks/use-gesture-handler.js.map +1 -1
  12. package/lib/commonjs/index.js +1 -1
  13. package/lib/commonjs/index.js.map +1 -1
  14. package/lib/commonjs/utils/get-circle-path.js +2 -0
  15. package/lib/commonjs/utils/get-circle-path.js.map +1 -1
  16. package/lib/commonjs/utils/get-rect-path.js +8 -5
  17. package/lib/commonjs/utils/get-rect-path.js.map +1 -1
  18. package/lib/commonjs/utils/unwrap-animated-value.js +7 -0
  19. package/lib/commonjs/utils/unwrap-animated-value.js.map +1 -1
  20. package/lib/module/canvas/canvas.js +59 -58
  21. package/lib/module/canvas/canvas.js.map +1 -1
  22. package/lib/module/canvas/context.js +1 -1
  23. package/lib/module/canvas/context.js.map +1 -1
  24. package/lib/module/components/index.js +4 -4
  25. package/lib/module/components/index.js.map +1 -1
  26. package/lib/module/hoc/with-touchable-handler.js +28 -34
  27. package/lib/module/hoc/with-touchable-handler.js.map +1 -1
  28. package/lib/module/hooks/use-gesture-handler.js +11 -5
  29. package/lib/module/hooks/use-gesture-handler.js.map +1 -1
  30. package/lib/module/index.js +1 -1
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/module/utils/get-circle-path.js +2 -0
  33. package/lib/module/utils/get-circle-path.js.map +1 -1
  34. package/lib/module/utils/get-rect-path.js +9 -6
  35. package/lib/module/utils/get-rect-path.js.map +1 -1
  36. package/lib/module/utils/unwrap-animated-value.js +7 -0
  37. package/lib/module/utils/unwrap-animated-value.js.map +1 -1
  38. package/lib/typescript/canvas/canvas.d.ts +6 -2
  39. package/lib/typescript/canvas/canvas.d.ts.map +1 -1
  40. package/lib/typescript/canvas/context.d.ts +6 -5
  41. package/lib/typescript/canvas/context.d.ts.map +1 -1
  42. package/lib/typescript/components/index.d.ts.map +1 -1
  43. package/lib/typescript/hoc/with-touchable-handler.d.ts +7 -9
  44. package/lib/typescript/hoc/with-touchable-handler.d.ts.map +1 -1
  45. package/lib/typescript/hooks/use-gesture-handler.d.ts +7 -8
  46. package/lib/typescript/hooks/use-gesture-handler.d.ts.map +1 -1
  47. package/lib/typescript/index.d.ts +1 -1
  48. package/lib/typescript/index.d.ts.map +1 -1
  49. package/lib/typescript/utils/get-circle-path.d.ts.map +1 -1
  50. package/lib/typescript/utils/get-rect-path.d.ts.map +1 -1
  51. package/lib/typescript/utils/unwrap-animated-value.d.ts +2 -1
  52. package/lib/typescript/utils/unwrap-animated-value.d.ts.map +1 -1
  53. package/package.json +6 -4
  54. package/src/canvas/canvas.tsx +96 -80
  55. package/src/canvas/context.tsx +19 -10
  56. package/src/components/index.ts +5 -4
  57. package/src/hoc/with-touchable-handler.tsx +40 -35
  58. package/src/hooks/use-gesture-handler.ts +25 -16
  59. package/src/index.ts +1 -1
  60. package/src/utils/get-circle-path.ts +1 -0
  61. package/src/utils/get-rect-path.ts +11 -6
  62. package/src/utils/unwrap-animated-value.ts +9 -1
@@ -1 +1 @@
1
- {"version":3,"file":"with-touchable-handler.d.ts","sourceRoot":"","sources":["../../../src/hoc/with-touchable-handler.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,SAAS,EAGf,MAAM,4BAA4B,CAAC;AAUpC,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IACxC,QAAQ,EAAE,CAAC,SAAS,EAAE,iBAAiB,GAAG,eAAe,KAAK,IAAI,CAAC;IACnE,KAAK,EAAE,CAAC,SAAS,EAAE,iBAAiB,GAAG,eAAe,KAAK,IAAI,CAAC;IAChE,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,yBAAyB,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAmBvE,QAAA,MAAM,oBAAoB,0DAC4B,WAAW,+IA2EhE,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"with-touchable-handler.d.ts","sourceRoot":"","sources":["../../../src/hoc/with-touchable-handler.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,MAAM,EAEZ,MAAM,4BAA4B,CAAC;AAWpC,OAAO,KAAK,EACV,uBAAuB,EACvB,kBAAkB,EAClB,6BAA6B,EAC9B,MAAM,8BAA8B,CAAC;AAEtC,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,CACP,SAAS,EAAE,uBAAuB,CAAC,6BAA6B,CAAC,KAC9D,IAAI,CAAC;IACV,QAAQ,EAAE,CACR,SAAS,EAAE,kBAAkB,CAAC,6BAA6B,CAAC,KACzD,IAAI,CAAC;IACV,KAAK,EAAE,CACL,SAAS,EAAE,uBAAuB,CAAC,6BAA6B,CAAC,KAC9D,IAAI,CAAC;IACV,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,yBAAyB,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEvE,eAAO,MAAM,WAAW,QAAS,MAAM,SAAS,GAAG,QAgBlD,CAAC;AAEF,QAAA,MAAM,oBAAoB,0DAC4B,WAAW,kBAC/C,MAAM,+IAyEvB,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
@@ -1,14 +1,13 @@
1
- import { type ExtendedTouchInfo, type TouchInfo } from '@shopify/react-native-skia';
2
- import type { TranslationInfo } from '../hoc';
1
+ import type { GestureStateChangeEvent, GestureUpdateEvent, PanGestureHandlerEventPayload } from 'react-native-gesture-handler';
3
2
  type UseGestureHandlerParams<ContextType> = {
4
- onStart?: (touchInfo: TouchInfo, context: ContextType) => void;
5
- onActive?: (extendedTouchInfo: ExtendedTouchInfo & TranslationInfo, context: ContextType) => void;
6
- onEnd?: (extendedTouchInfo: ExtendedTouchInfo & TranslationInfo, context: ContextType) => void;
3
+ onStart?: (touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>, context: ContextType) => void;
4
+ onActive?: (touchInfo: GestureUpdateEvent<PanGestureHandlerEventPayload>, context: ContextType) => void;
5
+ onEnd?: (touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>, context: ContextType) => void;
7
6
  };
8
7
  declare const useGestureHandler: <ContextType>(gestureHandlers: UseGestureHandlerParams<ContextType>) => {
9
- onStart: (touchInfo: TouchInfo) => void;
10
- onActive: (extendedTouchInfo: ExtendedTouchInfo & TranslationInfo) => void;
11
- onEnd: (extendedTouchInfo: ExtendedTouchInfo & TranslationInfo) => void;
8
+ onStart: (touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => void;
9
+ onActive: (extendedTouchInfo: GestureUpdateEvent<PanGestureHandlerEventPayload>) => void;
10
+ onEnd: (extendedTouchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => void;
12
11
  };
13
12
  export { useGestureHandler };
14
13
  //# sourceMappingURL=use-gesture-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-gesture-handler.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-gesture-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EAEf,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,KAAK,uBAAuB,CAAC,WAAW,IAAI;IAC1C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAC/D,QAAQ,CAAC,EAAE,CACT,iBAAiB,EAAE,iBAAiB,GAAG,eAAe,EACtD,OAAO,EAAE,WAAW,KACjB,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,CACN,iBAAiB,EAAE,iBAAiB,GAAG,eAAe,EACtD,OAAO,EAAE,WAAW,KACjB,IAAI,CAAC;CACX,CAAC;AAEF,QAAA,MAAM,iBAAiB;yBAQP,SAAS;kCAQD,iBAAiB,GAAG,eAAe;+BAQnC,iBAAiB,GAAG,eAAe;CAY1D,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"use-gesture-handler.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-gesture-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,uBAAuB,EACvB,kBAAkB,EAClB,6BAA6B,EAC9B,MAAM,8BAA8B,CAAC;AAEtC,KAAK,uBAAuB,CAAC,WAAW,IAAI;IAC1C,OAAO,CAAC,EAAE,CACR,SAAS,EAAE,uBAAuB,CAAC,6BAA6B,CAAC,EACjE,OAAO,EAAE,WAAW,KACjB,IAAI,CAAC;IACV,QAAQ,CAAC,EAAE,CACT,SAAS,EAAE,kBAAkB,CAAC,6BAA6B,CAAC,EAC5D,OAAO,EAAE,WAAW,KACjB,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,CACN,SAAS,EAAE,uBAAuB,CAAC,6BAA6B,CAAC,EACjE,OAAO,EAAE,WAAW,KACjB,IAAI,CAAC;CACX,CAAC;AAEF,QAAA,MAAM,iBAAiB;yBAQP,wBAAwB,6BAA6B,CAAC;kCAS9C,mBAAmB,6BAA6B,CAAC;+BAUhD,wBAAwB,6BAA6B,CAAC;CAc9E,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,5 +1,5 @@
1
+ import * as Touchable from './components';
1
2
  export * from './hoc';
2
3
  export * from './hooks/use-gesture-handler';
3
- import * as Touchable from './components';
4
4
  export default Touchable;
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,6BAA6B,CAAC;AAC5C,OAAO,KAAK,SAAS,MAAM,cAAc,CAAC;AAE1C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,cAAc,CAAC;AAC1C,cAAc,OAAO,CAAC;AACtB,cAAc,6BAA6B,CAAC;AAE5C,eAAe,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-circle-path.d.ts","sourceRoot":"","sources":["../../../src/utils/get-circle-path.ts"],"names":[],"mappings":"AAEA,KAAK,mBAAmB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,eAAO,MAAM,aAAa,kBAAmB,mBAAmB,gDAE/D,CAAC"}
1
+ {"version":3,"file":"get-circle-path.d.ts","sourceRoot":"","sources":["../../../src/utils/get-circle-path.ts"],"names":[],"mappings":"AAEA,KAAK,mBAAmB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,eAAO,MAAM,aAAa,kBAAmB,mBAAmB,gDAG/D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-rect-path.d.ts","sourceRoot":"","sources":["../../../src/utils/get-rect-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAE5E,KAAK,iBAAiB,GAClB;IACE,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,QAAA,MAAM,WAAW,WAAY,iBAAiB,gDAY7C,CAAC;AAEF,KAAK,wBAAwB,GAAG,iBAAiB,GAAG;IAClD,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,QAAA,MAAM,kBAAkB,WAAY,wBAAwB,gDAa3D,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"get-rect-path.d.ts","sourceRoot":"","sources":["../../../src/utils/get-rect-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAE/D,KAAK,iBAAiB,GAClB;IACE,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,QAAA,MAAM,WAAW,WAAY,iBAAiB,gDAc7C,CAAC;AAEF,KAAK,wBAAwB,GAAG,iBAAiB,GAAG;IAClD,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,QAAA,MAAM,kBAAkB,WAAY,wBAAwB,gDAgB3D,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC"}
@@ -1,9 +1,10 @@
1
1
  import type { SkiaValue } from '@shopify/react-native-skia';
2
+ import type Animated from 'react-native-reanimated';
2
3
  type SkiaValueWithSelector<T> = {
3
4
  value: SkiaValue<T>;
4
5
  selector: (v: T) => T;
5
6
  };
6
- declare const unwrapAnimatedValue: <T>(value: T | SkiaValue<T> | SkiaValueWithSelector<T>) => T;
7
+ declare const unwrapAnimatedValue: <T>(value: T | SkiaValue<T> | SkiaValueWithSelector<T> | Animated.SharedValue<T>) => T;
7
8
  declare const unwrapAnimatedValueObject: <T>(value: Record<any, T | SkiaValue<T>>) => Record<any, T>;
8
9
  export { unwrapAnimatedValue, unwrapAnimatedValueObject };
9
10
  //# sourceMappingURL=unwrap-animated-value.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"unwrap-animated-value.d.ts","sourceRoot":"","sources":["../../../src/utils/unwrap-animated-value.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D,KAAK,qBAAqB,CAAC,CAAC,IAAI;IAC9B,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACpB,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;CACvB,CAAC;AACF,QAAA,MAAM,mBAAmB,8DAaxB,CAAC;AAEF,QAAA,MAAM,yBAAyB,6DAM9B,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,CAAC"}
1
+ {"version":3,"file":"unwrap-animated-value.d.ts","sourceRoot":"","sources":["../../../src/utils/unwrap-animated-value.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AAEpD,KAAK,qBAAqB,CAAC,CAAC,IAAI;IAC9B,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACpB,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;CACvB,CAAC;AACF,QAAA,MAAM,mBAAmB,wFAmBxB,CAAC;AAEF,QAAA,MAAM,yBAAyB,6DAO9B,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-skia-gesture",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "A detection system for React Native Skia components",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -55,7 +55,7 @@
55
55
  "@evilmartians/lefthook": "^1.2.2",
56
56
  "@react-native-community/eslint-config": "^3.0.2",
57
57
  "@release-it/conventional-changelog": "^5.0.0",
58
- "@shopify/react-native-skia": "0.1.172",
58
+ "@shopify/react-native-skia": "0.1.221",
59
59
  "@types/jest": "^28.1.2",
60
60
  "@types/react": "18.0.26",
61
61
  "@types/react-native": "0.70.0",
@@ -70,6 +70,8 @@
70
70
  "react": "18.1.0",
71
71
  "react-native": "0.70.5",
72
72
  "react-native-builder-bob": "^0.20.0",
73
+ "react-native-gesture-handler": "~2.14.0",
74
+ "react-native-reanimated": "~3.6.2",
73
75
  "release-it": "^15.0.0",
74
76
  "typescript": "^4.5.2"
75
77
  },
@@ -81,9 +83,9 @@
81
83
  "react-native": "*"
82
84
  },
83
85
  "engines": {
84
- "node": ">= 16.0.0"
86
+ "node": ">= 18.0.0"
85
87
  },
86
- "packageManager": "^yarn@1.22.15",
88
+ "packageManager": "yarn@1.22.21",
87
89
  "jest": {
88
90
  "preset": "react-native",
89
91
  "modulePathIgnorePatterns": [
@@ -1,92 +1,108 @@
1
+ import { Canvas as SkiaCanvas } from '@shopify/react-native-skia';
2
+ import React, { useEffect, useMemo, useState } from 'react';
1
3
  import {
2
- Canvas as SkiaCanvas,
3
- type CanvasProps,
4
- useMultiTouchHandler,
5
- useValue,
6
- SkiaDomView,
7
- } from '@shopify/react-native-skia';
8
- import React, { useEffect } from 'react';
4
+ Gesture,
5
+ GestureDetector,
6
+ PanGesture,
7
+ } from 'react-native-gesture-handler';
8
+ import Animated, { useSharedValue } from 'react-native-reanimated';
9
+
9
10
  import {
10
11
  TouchHandlerContext,
11
12
  type TouchableHandlerContextType,
12
13
  } from './context';
13
14
 
14
- const Canvas = React.forwardRef<SkiaDomView, CanvasProps>(
15
- ({ children, onTouch, ...props }, ref) => {
16
- const touchableRefs = useValue<TouchableHandlerContextType['current']>({});
15
+ import type { CanvasProps } from '@shopify/react-native-skia';
16
+
17
+ type TouchableCanvasProps = CanvasProps & {
18
+ panGesture?: PanGesture;
19
+ };
20
+
21
+ const Canvas: React.FC<TouchableCanvasProps> = ({
22
+ children,
23
+ panGesture = Gesture.Pan(),
24
+ ...props
25
+ }) => {
26
+ // Instead of value, provide a subscribe method and reload the refs
27
+ const touchableRefs: TouchableHandlerContextType = useMemo(() => {
28
+ return { value: {} };
29
+ }, []);
30
+
31
+ const activeKey = useSharedValue<string[]>([]);
32
+
33
+ const [loadedRefs, prepareLoadedRefs] = useState<
34
+ TouchableHandlerContextType['value']
35
+ >({});
36
+
37
+ setTimeout(() => {
38
+ prepareLoadedRefs(touchableRefs.value);
39
+ }, 1000);
40
+
41
+ const mainGesture = panGesture
42
+ .onBegin((event) => {
43
+ const keys = Object.keys(loadedRefs);
44
+ for (let i = 0; i < keys.length; i++) {
45
+ const key = keys[i] as string;
46
+ const touchableItem = loadedRefs[key];
47
+ const isPointInPath = touchableItem?.isPointInPath(event);
48
+ if (isPointInPath && touchableItem?.onStart) {
49
+ activeKey.value.push(`${key}__${event.handlerTag}`);
50
+ touchableItem.onStart?.(event);
51
+ }
52
+ }
53
+ })
54
+ .onUpdate((event) => {
55
+ const activatedKey = activeKey.value.find((key) =>
56
+ key.includes(event.handlerTag.toString())
57
+ );
58
+
59
+ if (!activatedKey) {
60
+ return;
61
+ }
62
+ const indexedKey = activatedKey.split('__')?.[0];
17
63
 
18
- const activeKey = useValue<string[]>([]);
64
+ if (!indexedKey) {
65
+ return;
66
+ }
67
+ const touchableItem = loadedRefs[indexedKey];
19
68
 
20
- const touchHandler = useMultiTouchHandler(
21
- {
22
- onStart: (event) => {
23
- const keys = Object.keys(touchableRefs.current);
24
- for (let i = 0; i < keys.length; i++) {
25
- const key = keys[i] as string;
26
- const touchableItem = touchableRefs.current[key];
27
- if (touchableItem?.isPointInPath(event)) {
28
- activeKey.current.push(`${key}__${event.id}`);
29
- touchableItem.onStart?.(event);
30
- return;
31
- }
32
- }
33
- },
34
- onActive: (event) => {
35
- const activatedKey = activeKey.current.find((key) =>
36
- key.includes(event.id.toString())
37
- );
38
- if (!activatedKey) {
39
- return;
40
- }
41
- const indexedKey = activatedKey.split('__')?.[0];
42
- if (!indexedKey) {
43
- return;
44
- }
45
- const touchableItem = touchableRefs.current[indexedKey];
46
- return touchableItem?.onActive?.(event);
47
- },
48
- onEnd: (event) => {
49
- const activatedKey = activeKey.current.find((key) =>
50
- key.includes(event.id.toString())
51
- );
52
- if (!activatedKey) {
53
- return;
54
- }
55
- const indexedKey = activatedKey.split('__')?.[0];
56
- if (!indexedKey) {
57
- return;
58
- }
59
- const touchableItem = touchableRefs.current[indexedKey];
60
- activeKey.current = activeKey.current.filter(
61
- (key) => !key.includes(event.id.toString())
62
- );
63
- return touchableItem?.onEnd?.(event);
64
- },
65
- },
66
- [touchableRefs, activeKey]
67
- );
69
+ return touchableItem?.onActive?.(event);
70
+ })
71
+ .onFinalize((event) => {
72
+ const activatedKey = activeKey.value.find((key) =>
73
+ key.includes(event.handlerTag.toString())
74
+ );
75
+ if (!activatedKey) {
76
+ return;
77
+ }
78
+ const indexedKey = activatedKey.split('__')?.[0];
79
+ if (!indexedKey) {
80
+ return;
81
+ }
82
+ const touchableItem = loadedRefs[indexedKey];
83
+ activeKey.value = activeKey.value.filter(
84
+ (key) => !key.includes(event.handlerTag.toString())
85
+ );
86
+ return touchableItem?.onEnd?.(event as any);
87
+ });
68
88
 
69
- useEffect(() => {
70
- return () => {
71
- touchableRefs.current = {};
72
- };
73
- }, [touchableRefs]);
89
+ useEffect(() => {
90
+ return () => {
91
+ touchableRefs.value = {};
92
+ };
93
+ }, [touchableRefs]);
74
94
 
75
- return (
76
- <SkiaCanvas
77
- ref={ref as React.RefObject<SkiaDomView> & React.Ref<SkiaDomView>}
78
- {...props}
79
- onTouch={(touchInfo) => {
80
- touchHandler(touchInfo);
81
- return onTouch?.(touchInfo);
82
- }}
83
- >
84
- <TouchHandlerContext.Provider value={touchableRefs}>
85
- {children}
86
- </TouchHandlerContext.Provider>
87
- </SkiaCanvas>
88
- );
89
- }
90
- );
95
+ return (
96
+ <GestureDetector gesture={mainGesture}>
97
+ <Animated.View>
98
+ <SkiaCanvas {...props}>
99
+ <TouchHandlerContext.Provider value={touchableRefs}>
100
+ {children}
101
+ </TouchHandlerContext.Provider>
102
+ </SkiaCanvas>
103
+ </Animated.View>
104
+ </GestureDetector>
105
+ );
106
+ };
91
107
 
92
108
  export { Canvas };
@@ -1,23 +1,32 @@
1
- import type {
2
- ExtendedTouchInfo,
3
- TouchInfo,
4
- Vector,
5
- } from '@shopify/react-native-skia';
6
1
  import React, { useContext } from 'react';
7
2
 
3
+ import type { Vector } from '@shopify/react-native-skia';
4
+ import type {
5
+ GestureStateChangeEvent,
6
+ GestureUpdateEvent,
7
+ PanGestureHandlerEventPayload,
8
+ } from 'react-native-gesture-handler';
9
+
8
10
  export type TouchableHandlerContextType = {
9
- current: Record<
11
+ value: Record<
10
12
  string,
11
13
  {
12
- onStart: (touchInfo: TouchInfo) => void;
13
- onActive: (touchInfo: ExtendedTouchInfo) => void;
14
- onEnd: (touchInfo: ExtendedTouchInfo) => void;
14
+ onStart: (
15
+ touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>
16
+ ) => void;
17
+ onActive: (
18
+ touchInfo: GestureUpdateEvent<PanGestureHandlerEventPayload>
19
+ ) => void;
20
+ onEnd: (
21
+ touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>
22
+ ) => void;
15
23
  isPointInPath: (point: Vector) => boolean;
16
24
  }
17
25
  >;
18
26
  };
27
+
19
28
  const TouchHandlerContext = React.createContext<TouchableHandlerContextType>({
20
- current: {},
29
+ value: {},
21
30
  });
22
31
 
23
32
  const useTouchHandlerContext = () => {
@@ -4,11 +4,12 @@ import {
4
4
  Rect as SkiaRect,
5
5
  Path as SkiaPath,
6
6
  } from '@shopify/react-native-skia';
7
+
7
8
  import { withTouchableHandler } from '../hoc';
8
9
 
9
10
  export { Canvas } from '../canvas';
10
11
 
11
- export const Circle = withTouchableHandler(SkiaCircle);
12
- export const RoundedRect = withTouchableHandler(SkiaRoundedRect);
13
- export const Rect = withTouchableHandler(SkiaRect);
14
- export const Path = withTouchableHandler(SkiaPath);
12
+ export const Circle = withTouchableHandler(SkiaCircle, 'Circle');
13
+ export const RoundedRect = withTouchableHandler(SkiaRoundedRect, 'RoundedRect');
14
+ export const Rect = withTouchableHandler(SkiaRect, 'Rect');
15
+ export const Path = withTouchableHandler(SkiaPath, 'Path');
@@ -1,37 +1,43 @@
1
1
  import {
2
- type ExtendedTouchInfo,
3
2
  type SkiaValue,
4
3
  type SkPath,
5
- type TouchInfo,
6
4
  type Vector,
7
- useValue,
8
5
  } from '@shopify/react-native-skia';
9
6
  import { useCallback, useEffect, useId } from 'react';
7
+
8
+ import { useTouchHandlerContext } from '../canvas/context';
10
9
  import { getCirclePath } from '../utils/get-circle-path';
11
10
  import { getRectPath, getRoundedRectPath } from '../utils/get-rect-path';
12
11
  import {
13
12
  unwrapAnimatedValue,
14
13
  unwrapAnimatedValueObject,
15
14
  } from '../utils/unwrap-animated-value';
16
- import { useTouchHandlerContext } from '../canvas/context';
17
15
 
18
- export type TranslationInfo = {
19
- translationX: number;
20
- translationY: number;
21
- };
16
+ import type {
17
+ GestureStateChangeEvent,
18
+ GestureUpdateEvent,
19
+ PanGestureHandlerEventPayload,
20
+ } from 'react-native-gesture-handler';
22
21
 
23
22
  export type TouchableHandlerProps = {
24
- onStart: (touchInfo: TouchInfo) => void;
25
- onActive: (touchInfo: ExtendedTouchInfo & TranslationInfo) => void;
26
- onEnd: (touchInfo: ExtendedTouchInfo & TranslationInfo) => void;
23
+ onStart: (
24
+ touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>
25
+ ) => void;
26
+ onActive: (
27
+ touchInfo: GestureUpdateEvent<PanGestureHandlerEventPayload>
28
+ ) => void;
29
+ onEnd: (
30
+ touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>
31
+ ) => void;
27
32
  touchablePath: SkPath | SkiaValue<SkPath>;
28
33
  };
29
34
 
30
35
  type WithTouchableHandlerProps<T> = T & Partial<TouchableHandlerProps>;
31
36
 
32
- const getSkiaPath = (key: string, props: any) => {
33
- const unwrappedProps = unwrapAnimatedValueObject(props) as any;
37
+ export const getSkiaPath = (key: string, props: any) => {
38
+ 'worklet';
34
39
 
40
+ const unwrappedProps = unwrapAnimatedValueObject(props) as any;
35
41
  switch (key) {
36
42
  case 'Circle':
37
43
  return getCirclePath(unwrappedProps);
@@ -47,7 +53,8 @@ const getSkiaPath = (key: string, props: any) => {
47
53
  };
48
54
 
49
55
  const withTouchableHandler = <T,>(
50
- Component: (props: WithTouchableHandlerProps<T>) => JSX.Element
56
+ Component: (props: WithTouchableHandlerProps<T>) => JSX.Element,
57
+ componentName?: string
51
58
  ) => {
52
59
  return ({
53
60
  onStart: onStartProp,
@@ -59,42 +66,37 @@ const withTouchableHandler = <T,>(
59
66
  const id = useId();
60
67
  const ref = useTouchHandlerContext();
61
68
 
62
- const startingPoint = useValue<Vector | null>(null);
63
-
64
69
  const onStart: TouchableHandlerProps['onStart'] = useCallback(
65
70
  (event) => {
66
- startingPoint.current = { x: event.x, y: event.y };
71
+ 'worklet';
67
72
  return onStartProp?.(event);
68
73
  },
69
- [onStartProp, startingPoint]
74
+ [onStartProp]
70
75
  );
71
76
  const onActive: TouchableHandlerProps['onActive'] = useCallback(
72
77
  (event) => {
73
- const translationX = event.x - (startingPoint.current?.x ?? 0);
74
- const translationY = event.y - (startingPoint.current?.y ?? 0);
75
- return onActiveProp?.({
76
- ...event,
77
- translationX,
78
- translationY,
79
- });
78
+ 'worklet';
79
+ return onActiveProp?.(event);
80
80
  },
81
- [onActiveProp, startingPoint]
81
+ [onActiveProp]
82
82
  );
83
83
  const onEnd: TouchableHandlerProps['onEnd'] = useCallback(
84
84
  (event) => {
85
- const translationX = event.x - (startingPoint.current?.x ?? 0);
86
- const translationY = event.y - (startingPoint.current?.y ?? 0);
87
- return onEndProp?.({ ...event, translationX, translationY });
85
+ 'worklet';
86
+ return onEndProp?.(event);
88
87
  },
89
- [onEndProp, startingPoint]
88
+ [onEndProp]
90
89
  );
91
90
 
92
91
  const isPointInPath = useCallback(
93
92
  (point: Vector) => {
93
+ 'worklet';
94
94
  if (touchablePath) {
95
95
  return unwrapAnimatedValue(touchablePath).contains(point.x, point.y);
96
96
  }
97
- const path = getSkiaPath(Component.name, props);
97
+
98
+ if (!componentName) return false;
99
+ const path = getSkiaPath(componentName, props);
98
100
 
99
101
  if (!path) {
100
102
  throw Error('No touchablePath provided');
@@ -105,20 +107,23 @@ const withTouchableHandler = <T,>(
105
107
  );
106
108
 
107
109
  useEffect(() => {
108
- ref.current = {
110
+ ref.value = {
109
111
  [`id:${id}`]: {
110
112
  isPointInPath,
111
113
  onStart,
112
114
  onActive,
113
115
  onEnd,
114
116
  },
115
- ...ref.current,
117
+ ...ref.value,
116
118
  } as any;
119
+ // eslint-disable-next-line react-hooks/exhaustive-deps
120
+ }, [id, isPointInPath, onActive, onEnd, onStart]);
117
121
 
122
+ useEffect(() => {
118
123
  return () => {
119
- delete ref.current?.[id];
124
+ delete ref.value?.[`id:${id}`];
120
125
  };
121
- }, [id, isPointInPath, onActive, onEnd, onStart, ref, touchablePath]);
126
+ }, [id, props, ref, touchablePath]);
122
127
 
123
128
  return Component(props as any);
124
129
  };
@@ -1,19 +1,23 @@
1
- import {
2
- type ExtendedTouchInfo,
3
- type TouchInfo,
4
- useValue,
5
- } from '@shopify/react-native-skia';
6
1
  import { useCallback } from 'react';
7
- import type { TranslationInfo } from '../hoc';
2
+ import { useSharedValue } from 'react-native-reanimated';
3
+
4
+ import type {
5
+ GestureStateChangeEvent,
6
+ GestureUpdateEvent,
7
+ PanGestureHandlerEventPayload,
8
+ } from 'react-native-gesture-handler';
8
9
 
9
10
  type UseGestureHandlerParams<ContextType> = {
10
- onStart?: (touchInfo: TouchInfo, context: ContextType) => void;
11
+ onStart?: (
12
+ touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>,
13
+ context: ContextType
14
+ ) => void;
11
15
  onActive?: (
12
- extendedTouchInfo: ExtendedTouchInfo & TranslationInfo,
16
+ touchInfo: GestureUpdateEvent<PanGestureHandlerEventPayload>,
13
17
  context: ContextType
14
18
  ) => void;
15
19
  onEnd?: (
16
- extendedTouchInfo: ExtendedTouchInfo & TranslationInfo,
20
+ touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>,
17
21
  context: ContextType
18
22
  ) => void;
19
23
  };
@@ -23,28 +27,33 @@ const useGestureHandler = <ContextType>(
23
27
  ) => {
24
28
  const { onStart, onActive, onEnd } = gestureHandlers;
25
29
 
26
- const context = useValue<ContextType>({} as any);
30
+ const context = useSharedValue<ContextType>({} as any);
27
31
 
28
32
  const handleStart = useCallback(
29
- (touchInfo: TouchInfo) => {
33
+ (touchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
34
+ 'worklet';
30
35
  if (!onStart) return;
31
- return onStart(touchInfo, context.current);
36
+ return onStart(touchInfo, context.value);
32
37
  },
33
38
  [context, onStart]
34
39
  );
35
40
 
36
41
  const handleActive = useCallback(
37
- (extendedTouchInfo: ExtendedTouchInfo & TranslationInfo) => {
42
+ (extendedTouchInfo: GestureUpdateEvent<PanGestureHandlerEventPayload>) => {
43
+ 'worklet';
38
44
  if (!onActive) return;
39
- return onActive(extendedTouchInfo, context.current);
45
+ return onActive(extendedTouchInfo, context.value);
40
46
  },
41
47
  [context, onActive]
42
48
  );
43
49
 
44
50
  const handleEnd = useCallback(
45
- (extendedTouchInfo: ExtendedTouchInfo & TranslationInfo) => {
51
+ (
52
+ extendedTouchInfo: GestureStateChangeEvent<PanGestureHandlerEventPayload>
53
+ ) => {
54
+ 'worklet';
46
55
  if (!onEnd) return;
47
- return onEnd(extendedTouchInfo, context.current);
56
+ return onEnd(extendedTouchInfo, context.value);
48
57
  },
49
58
  [context, onEnd]
50
59
  );
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import * as Touchable from './components';
1
2
  export * from './hoc';
2
3
  export * from './hooks/use-gesture-handler';
3
- import * as Touchable from './components';
4
4
 
5
5
  export default Touchable;
@@ -3,5 +3,6 @@ import { Skia } from '@shopify/react-native-skia';
3
3
  type GetCirclePathParams = { cx: number; cy: number; r: number };
4
4
 
5
5
  export const getCirclePath = ({ cx, cy, r }: GetCirclePathParams) => {
6
+ 'worklet';
6
7
  return Skia.Path.Make().addCircle(cx, cy, r);
7
8
  };
@@ -1,4 +1,4 @@
1
- import { rect, rrect, Skia, type SkRect } from '@shopify/react-native-skia';
1
+ import { Skia, type SkRect } from '@shopify/react-native-skia';
2
2
 
3
3
  type GetRectPathParams =
4
4
  | {
@@ -10,16 +10,18 @@ type GetRectPathParams =
10
10
  | { rect: SkRect };
11
11
 
12
12
  const getRectPath = (params: GetRectPathParams) => {
13
+ 'worklet';
14
+
13
15
  const skPath = Skia.Path.Make();
14
16
  if ('rect' in params) {
15
- // eslint-disable-next-line @typescript-eslint/no-shadow
16
17
  const { rect } = params;
17
18
 
18
19
  skPath.addRect(rect);
19
20
  return skPath;
20
21
  }
21
22
  const { x, y, width, height } = params;
22
- skPath.addRect(rect(x, y, width, height));
23
+
24
+ skPath.addRect(Skia.XYWHRect(x, y, width, height));
23
25
  return skPath;
24
26
  };
25
27
 
@@ -28,17 +30,20 @@ type GetRoundedRectPathParams = GetRectPathParams & {
28
30
  };
29
31
 
30
32
  const getRoundedRectPath = (params: GetRoundedRectPathParams) => {
33
+ 'worklet';
34
+
31
35
  const { r } = params;
32
36
  const skPath = Skia.Path.Make();
33
37
  if ('rect' in params) {
34
- // eslint-disable-next-line @typescript-eslint/no-shadow
35
38
  const { rect } = params;
36
- skPath.addRRect(rrect(rect, r, r));
39
+
40
+ skPath.addRRect(Skia.RRectXY(rect, r, r));
37
41
  return skPath;
38
42
  }
39
43
  const { x, y, width, height } = params;
40
44
 
41
- skPath.addRRect(rrect(rect(x, y, width, height), r, r));
45
+ const roundedRect = Skia.RRectXY(Skia.XYWHRect(x, y, width, height), r, r);
46
+ skPath.addRRect(roundedRect);
42
47
  return skPath;
43
48
  };
44
49