react-native-skia-gesture 0.1.6

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 (73) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +121 -0
  3. package/lib/commonjs/canvas/canvas.js +64 -0
  4. package/lib/commonjs/canvas/canvas.js.map +1 -0
  5. package/lib/commonjs/canvas/context.js +18 -0
  6. package/lib/commonjs/canvas/context.js.map +1 -0
  7. package/lib/commonjs/canvas/index.js +17 -0
  8. package/lib/commonjs/canvas/index.js.map +1 -0
  9. package/lib/commonjs/hoc/index.js +17 -0
  10. package/lib/commonjs/hoc/index.js.map +1 -0
  11. package/lib/commonjs/hoc/with-touchable-handler.js +94 -0
  12. package/lib/commonjs/hoc/with-touchable-handler.js.map +1 -0
  13. package/lib/commonjs/hooks/use-gesture-handler.js +35 -0
  14. package/lib/commonjs/hooks/use-gesture-handler.js.map +1 -0
  15. package/lib/commonjs/index.js +39 -0
  16. package/lib/commonjs/index.js.map +1 -0
  17. package/lib/commonjs/utils/get-circle-path.js +17 -0
  18. package/lib/commonjs/utils/get-circle-path.js.map +1 -0
  19. package/lib/commonjs/utils/get-rect-path.js +48 -0
  20. package/lib/commonjs/utils/get-rect-path.js.map +1 -0
  21. package/lib/commonjs/utils/unwrap-animated-value.js +23 -0
  22. package/lib/commonjs/utils/unwrap-animated-value.js.map +1 -0
  23. package/lib/module/canvas/canvas.js +56 -0
  24. package/lib/module/canvas/canvas.js.map +1 -0
  25. package/lib/module/canvas/context.js +9 -0
  26. package/lib/module/canvas/context.js.map +1 -0
  27. package/lib/module/canvas/index.js +2 -0
  28. package/lib/module/canvas/index.js.map +1 -0
  29. package/lib/module/hoc/index.js +2 -0
  30. package/lib/module/hoc/index.js.map +1 -0
  31. package/lib/module/hoc/with-touchable-handler.js +88 -0
  32. package/lib/module/hoc/with-touchable-handler.js.map +1 -0
  33. package/lib/module/hooks/use-gesture-handler.js +29 -0
  34. package/lib/module/hooks/use-gesture-handler.js.map +1 -0
  35. package/lib/module/index.js +4 -0
  36. package/lib/module/index.js.map +1 -0
  37. package/lib/module/utils/get-circle-path.js +10 -0
  38. package/lib/module/utils/get-circle-path.js.map +1 -0
  39. package/lib/module/utils/get-rect-path.js +41 -0
  40. package/lib/module/utils/get-rect-path.js.map +1 -0
  41. package/lib/module/utils/unwrap-animated-value.js +16 -0
  42. package/lib/module/utils/unwrap-animated-value.js.map +1 -0
  43. package/lib/typescript/canvas/canvas.d.ts +5 -0
  44. package/lib/typescript/canvas/canvas.d.ts.map +1 -0
  45. package/lib/typescript/canvas/context.d.ts +14 -0
  46. package/lib/typescript/canvas/context.d.ts.map +1 -0
  47. package/lib/typescript/canvas/index.d.ts +2 -0
  48. package/lib/typescript/canvas/index.d.ts.map +1 -0
  49. package/lib/typescript/hoc/index.d.ts +2 -0
  50. package/lib/typescript/hoc/index.d.ts.map +1 -0
  51. package/lib/typescript/hoc/with-touchable-handler.d.ts +15 -0
  52. package/lib/typescript/hoc/with-touchable-handler.d.ts.map +1 -0
  53. package/lib/typescript/hooks/use-gesture-handler.d.ts +14 -0
  54. package/lib/typescript/hooks/use-gesture-handler.d.ts.map +1 -0
  55. package/lib/typescript/index.d.ts +4 -0
  56. package/lib/typescript/index.d.ts.map +1 -0
  57. package/lib/typescript/utils/get-circle-path.d.ts +8 -0
  58. package/lib/typescript/utils/get-circle-path.d.ts.map +1 -0
  59. package/lib/typescript/utils/get-rect-path.d.ts +16 -0
  60. package/lib/typescript/utils/get-rect-path.d.ts.map +1 -0
  61. package/lib/typescript/utils/unwrap-animated-value.d.ts +5 -0
  62. package/lib/typescript/utils/unwrap-animated-value.d.ts.map +1 -0
  63. package/package.json +160 -0
  64. package/src/canvas/canvas.tsx +66 -0
  65. package/src/canvas/context.tsx +27 -0
  66. package/src/canvas/index.ts +1 -0
  67. package/src/hoc/index.ts +1 -0
  68. package/src/hoc/with-touchable-handler.tsx +127 -0
  69. package/src/hooks/use-gesture-handler.ts +59 -0
  70. package/src/index.ts +3 -0
  71. package/src/utils/get-circle-path.ts +7 -0
  72. package/src/utils/get-rect-path.ts +41 -0
  73. package/src/utils/unwrap-animated-value.ts +18 -0
@@ -0,0 +1,127 @@
1
+ import {
2
+ ExtendedTouchInfo,
3
+ SkiaProps,
4
+ SkiaValue,
5
+ SkPath,
6
+ TouchInfo,
7
+ useValue,
8
+ Vector,
9
+ } from '@shopify/react-native-skia';
10
+ import { useCallback, useEffect, useId } from 'react';
11
+ import { getCirclePath } from '../utils/get-circle-path';
12
+ import { getRectPath, getRoundedRectPath } from '../utils/get-rect-path';
13
+ import {
14
+ unwrapAnimatedValue,
15
+ unwrapAnimatedValueObject,
16
+ } from '../utils/unwrap-animated-value';
17
+ import { useTouchHandlerContext } from '../canvas/context';
18
+
19
+ export type TranslationInfo = {
20
+ translationX: number;
21
+ translationY: number;
22
+ };
23
+
24
+ export type TouchableHandlerProps = {
25
+ onStart: (touchInfo: TouchInfo) => void;
26
+ onActive: (touchInfo: ExtendedTouchInfo & TranslationInfo) => void;
27
+ onEnd: (touchInfo: ExtendedTouchInfo & TranslationInfo) => void;
28
+ touchablePath: SkPath | SkiaValue<SkPath>;
29
+ };
30
+
31
+ type WithTouchableHandlerProps<T> = SkiaProps<T> &
32
+ Partial<TouchableHandlerProps>;
33
+
34
+ const getSkiaPath = (key: string, props: any) => {
35
+ const unwrappedProps = unwrapAnimatedValueObject(props) as any;
36
+
37
+ switch (key) {
38
+ case 'Circle':
39
+ return getCirclePath(unwrappedProps);
40
+ case 'Rect':
41
+ return getRectPath(unwrappedProps);
42
+ case 'RoundedRect':
43
+ return getRoundedRectPath(unwrappedProps);
44
+ default:
45
+ return null;
46
+ }
47
+ };
48
+
49
+ const withTouchableHandler = <T,>(
50
+ Component: (props: WithTouchableHandlerProps<T>) => JSX.Element
51
+ ) => {
52
+ return ({
53
+ onStart: onStartProp,
54
+ onActive: onActiveProp,
55
+ onEnd: onEndProp,
56
+ touchablePath,
57
+ ...props
58
+ }: WithTouchableHandlerProps<T>) => {
59
+ const id = useId();
60
+ const ref = useTouchHandlerContext();
61
+
62
+ const startingPoint = useValue<Vector | null>(null);
63
+
64
+ const onStart: TouchableHandlerProps['onStart'] = useCallback(
65
+ (event) => {
66
+ startingPoint.current = { x: event.x, y: event.y };
67
+ return onStartProp?.(event);
68
+ },
69
+ [onStartProp, startingPoint]
70
+ );
71
+ const onActive: TouchableHandlerProps['onActive'] = useCallback(
72
+ (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
+ });
80
+ },
81
+ [onActiveProp, startingPoint]
82
+ );
83
+ const onEnd: TouchableHandlerProps['onEnd'] = useCallback(
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 });
88
+ },
89
+ [onEndProp, startingPoint]
90
+ );
91
+
92
+ const isPointInPath = useCallback(
93
+ (point: Vector) => {
94
+ if (touchablePath) {
95
+ return unwrapAnimatedValue(touchablePath).contains(point.x, point.y);
96
+ }
97
+
98
+ const path = getSkiaPath(Component.name, props);
99
+ if (!path) {
100
+ throw Error('No touchablePath provided');
101
+ }
102
+ return path.contains(point.x, point.y);
103
+ },
104
+ [props, touchablePath]
105
+ );
106
+
107
+ useEffect(() => {
108
+ ref.current = {
109
+ [`id:${id}`]: {
110
+ isPointInPath,
111
+ onStart,
112
+ onActive,
113
+ onEnd,
114
+ },
115
+ ...ref.current,
116
+ } as any;
117
+
118
+ return () => {
119
+ delete ref.current?.[id];
120
+ };
121
+ }, [id, isPointInPath, onActive, onEnd, onStart, ref, touchablePath]);
122
+
123
+ return Component(props as any);
124
+ };
125
+ };
126
+
127
+ export { withTouchableHandler };
@@ -0,0 +1,59 @@
1
+ import {
2
+ ExtendedTouchInfo,
3
+ TouchInfo,
4
+ useValue,
5
+ } from '@shopify/react-native-skia';
6
+ import { useCallback } from 'react';
7
+ import type { TranslationInfo } from '../hoc';
8
+
9
+ type UseGestureHandlerParams<ContextType> = {
10
+ onStart?: (touchInfo: TouchInfo, context: ContextType) => void;
11
+ onActive?: (
12
+ extendedTouchInfo: ExtendedTouchInfo & TranslationInfo,
13
+ context: ContextType
14
+ ) => void;
15
+ onEnd?: (
16
+ extendedTouchInfo: ExtendedTouchInfo & TranslationInfo,
17
+ context: ContextType
18
+ ) => void;
19
+ };
20
+
21
+ const useGestureHandler = <ContextType>(
22
+ gestureHandlers: UseGestureHandlerParams<ContextType>
23
+ ) => {
24
+ const { onStart, onActive, onEnd } = gestureHandlers;
25
+
26
+ const context = useValue<ContextType>({} as any);
27
+
28
+ const handleStart = useCallback(
29
+ (touchInfo: TouchInfo) => {
30
+ if (!onStart) return;
31
+ return onStart(touchInfo, context.current);
32
+ },
33
+ [context, onStart]
34
+ );
35
+
36
+ const handleActive = useCallback(
37
+ (extendedTouchInfo: ExtendedTouchInfo & TranslationInfo) => {
38
+ if (!onActive) return;
39
+ return onActive(extendedTouchInfo, context.current);
40
+ },
41
+ [context, onActive]
42
+ );
43
+
44
+ const handleEnd = useCallback(
45
+ (extendedTouchInfo: ExtendedTouchInfo & TranslationInfo) => {
46
+ if (!onEnd) return;
47
+ return onEnd(extendedTouchInfo, context.current);
48
+ },
49
+ [context, onEnd]
50
+ );
51
+
52
+ return {
53
+ onStart: handleStart,
54
+ onActive: handleActive,
55
+ onEnd: handleEnd,
56
+ };
57
+ };
58
+
59
+ export { useGestureHandler };
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './canvas';
2
+ export * from './hoc';
3
+ export * from './hooks/use-gesture-handler';
@@ -0,0 +1,7 @@
1
+ import { Skia } from '@shopify/react-native-skia';
2
+
3
+ type GetCirclePathParams = { cx: number; cy: number; r: number };
4
+
5
+ export const getCirclePath = ({ cx, cy, r }: GetCirclePathParams) => {
6
+ return Skia.Path.Make().addCircle(cx, cy, r);
7
+ };
@@ -0,0 +1,41 @@
1
+ import { rect, rrect, Skia, SkRect } from '@shopify/react-native-skia';
2
+
3
+ type GetRectPathParams =
4
+ | {
5
+ x: number;
6
+ y: number;
7
+ width: number;
8
+ height: number;
9
+ }
10
+ | { rect: SkRect };
11
+
12
+ const getRectPath = (params: GetRectPathParams) => {
13
+ const skPath = Skia.Path.Make();
14
+ if ('rect' in params) {
15
+ // eslint-disable-next-line @typescript-eslint/no-shadow
16
+ const { rect } = params;
17
+
18
+ skPath.addRect(rect);
19
+ return skPath;
20
+ }
21
+ const { x, y, width, height } = params;
22
+ skPath.addRect(rect(x, y, width, height));
23
+ return skPath;
24
+ };
25
+
26
+ type GetRoundedRectPathParams = GetRectPathParams & {
27
+ r: number;
28
+ };
29
+
30
+ const getRoundedRectPath = (params: GetRoundedRectPathParams) => {
31
+ const { r } = params;
32
+ if ('rect' in params) {
33
+ // eslint-disable-next-line @typescript-eslint/no-shadow
34
+ const { rect } = params;
35
+ return Skia.Path.Make().addRRect(rrect(rect, r, r));
36
+ }
37
+ const { x, y, width, height } = params;
38
+ return Skia.Path.Make().addRRect(rrect(rect(x, y, width, height), r, r));
39
+ };
40
+
41
+ export { getRectPath, getRoundedRectPath };
@@ -0,0 +1,18 @@
1
+ import type { SkiaValue } from '@shopify/react-native-skia';
2
+
3
+ const unwrapAnimatedValue = <T>(value: SkiaValue<T> | T): T => {
4
+ if ((value as SkiaValue<T>).current != null) {
5
+ return (value as SkiaValue<T>).current;
6
+ }
7
+ return value as T;
8
+ };
9
+
10
+ const unwrapAnimatedValueObject = <T>(
11
+ value: Record<any, SkiaValue<T> | T>
12
+ ): Record<any, T> => {
13
+ return Object.keys(value).reduce((acc, key) => {
14
+ return { ...acc, [key]: unwrapAnimatedValue(value[key]) };
15
+ }, {});
16
+ };
17
+
18
+ export { unwrapAnimatedValue, unwrapAnimatedValueObject };