1
- import React , {
2
- useEffect ,
1
+ import {
2
+ forwardRef ,
3
3
useCallback ,
4
+ useEffect ,
5
+ useImperativeHandle ,
4
6
useMemo ,
5
- forwardRef ,
6
7
useRef ,
7
8
} from "react" ;
8
- import type {
9
- RefObject ,
10
- ReactNode ,
11
- MutableRefObject ,
12
- ForwardedRef ,
13
- FunctionComponent ,
14
- } from "react" ;
15
- import type { LayoutChangeEvent } from "react-native" ;
9
+ import type { LayoutChangeEvent , ViewProps } from "react-native" ;
10
+ import type { SharedValue } from "react-native-reanimated" ;
16
11
17
- import { SkiaDomView } from "../views" ;
12
+ import { SkiaViewNativeId } from "../views/SkiaViewNativeId" ;
13
+ import SkiaPictureViewNativeComponent from "../specs/SkiaPictureViewNativeComponent" ;
14
+ import type { SkRect , SkSize } from "../skia/types" ;
15
+ import { SkiaSGRoot } from "../sksg/Reconciler" ;
16
+ import { Skia } from "../skia" ;
18
17
import type { SkiaBaseViewProps } from "../views" ;
19
18
20
- import { SkiaRoot } from "./Reconciler" ;
21
-
22
- export const useCanvasRef = ( ) => useRef < SkiaDomView > ( null ) ;
23
-
24
- export interface CanvasProps extends SkiaBaseViewProps {
25
- ref ?: RefObject < SkiaDomView > ;
26
- children : ReactNode ;
27
- mode ?: "default" | "continuous" ;
28
- }
19
+ const NativeSkiaPictureView = SkiaPictureViewNativeComponent ;
29
20
21
+ // TODO: no need to go through the JS thread for this
30
22
const useOnSizeEvent = (
31
23
resultValue : SkiaBaseViewProps [ "onSize" ] ,
32
24
onLayout ?: ( event : LayoutChangeEvent ) => void
@@ -46,81 +38,91 @@ const useOnSizeEvent = (
46
38
) ;
47
39
} ;
48
40
49
- export const Canvas = forwardRef < SkiaDomView , CanvasProps > (
41
+ export interface CanvasProps extends ViewProps {
42
+ debug ?: boolean ;
43
+ opaque ?: boolean ;
44
+ onSize ?: SharedValue < SkSize > ;
45
+ mode ?: "continuous" | "default" ;
46
+ }
47
+
48
+ export const Canvas = forwardRef (
50
49
(
51
50
{
52
- children,
53
- style,
51
+ mode,
54
52
debug,
55
- mode = "default" ,
56
- onSize : _onSize ,
53
+ opaque,
54
+ children,
55
+ onSize,
57
56
onLayout : _onLayout ,
58
- ...props
59
- } ,
60
- forwardedRef
57
+ ...viewProps
58
+ } : CanvasProps ,
59
+ ref
61
60
) => {
62
- const onLayout = useOnSizeEvent ( _onSize , _onLayout ) ;
63
- const innerRef = useCanvasRef ( ) ;
64
- const ref = useCombinedRefs ( forwardedRef , innerRef ) ;
65
- const redraw = useCallback ( ( ) => {
66
- innerRef . current ?. redraw ( ) ;
67
- } , [ innerRef ] ) ;
68
- const getNativeId = useCallback ( ( ) => {
69
- const id = innerRef . current ?. nativeId ?? - 1 ;
70
- return id ;
71
- } , [ innerRef ] ) ;
61
+ const rafId = useRef < number | null > ( null ) ;
62
+ const onLayout = useOnSizeEvent ( onSize , _onLayout ) ;
63
+ // Native ID
64
+ const nativeId = useMemo ( ( ) => {
65
+ return SkiaViewNativeId . current ++ ;
66
+ } , [ ] ) ;
72
67
73
- const root = useMemo (
74
- ( ) => new SkiaRoot ( redraw , getNativeId ) ,
75
- [ redraw , getNativeId ]
76
- ) ;
68
+ // Root
69
+ const root = useMemo ( ( ) => new SkiaSGRoot ( Skia , nativeId ) , [ nativeId ] ) ;
77
70
78
- // Render effect
71
+ // Render effects
79
72
useEffect ( ( ) => {
80
73
root . render ( children ) ;
81
- } , [ children , root , redraw ] ) ;
74
+ } , [ children , root ] ) ;
82
75
83
76
useEffect ( ( ) => {
84
77
return ( ) => {
85
78
root . unmount ( ) ;
86
79
} ;
87
80
} , [ root ] ) ;
88
81
82
+ const requestRedraw = useCallback ( ( ) => {
83
+ rafId . current = requestAnimationFrame ( ( ) => {
84
+ root . render ( children ) ;
85
+ if ( mode === "continuous" ) {
86
+ requestRedraw ( ) ;
87
+ }
88
+ } ) ;
89
+ } , [ children , mode , root ] ) ;
90
+
91
+ useEffect ( ( ) => {
92
+ if ( mode === "continuous" ) {
93
+ console . warn ( "The `mode` property in `Canvas` is deprecated." ) ;
94
+ requestRedraw ( ) ;
95
+ }
96
+ return ( ) => {
97
+ if ( rafId . current !== null ) {
98
+ cancelAnimationFrame ( rafId . current ) ;
99
+ }
100
+ } ;
101
+ } , [ mode , requestRedraw ] ) ;
102
+ // Component methods
103
+ useImperativeHandle ( ref , ( ) => ( {
104
+ makeImageSnapshot : ( rect ?: SkRect ) => {
105
+ return SkiaViewApi . makeImageSnapshot ( nativeId , rect ) ;
106
+ } ,
107
+ makeImageSnapshotAsync : ( rect ?: SkRect ) => {
108
+ return SkiaViewApi . makeImageSnapshotAsync ( nativeId , rect ) ;
109
+ } ,
110
+ redraw : ( ) => {
111
+ SkiaViewApi . requestRedraw ( nativeId ) ;
112
+ } ,
113
+ getNativeId : ( ) => {
114
+ return nativeId ;
115
+ } ,
116
+ } ) ) ;
89
117
return (
90
- < SkiaDomView
91
- ref = { ref }
92
- style = { style }
93
- root = { root . dom }
94
- onLayout = { onLayout }
118
+ < NativeSkiaPictureView
119
+ collapsable = { false }
120
+ nativeID = { `${ nativeId } ` }
95
121
debug = { debug }
96
- mode = { mode }
97
- { ...props }
122
+ opaque = { opaque }
123
+ onLayout = { onLayout }
124
+ { ...viewProps }
98
125
/>
99
126
) ;
100
127
}
101
- ) as FunctionComponent < CanvasProps & React . RefAttributes < SkiaDomView > > ;
102
-
103
- /**
104
- * Combines a list of refs into a single ref. This can be used to provide
105
- * both a forwarded ref and an internal ref keeping the same functionality
106
- * on both of the refs.
107
- * @param refs Array of refs to combine
108
- * @returns A single ref that can be used in a ref prop.
109
- */
110
- const useCombinedRefs = < T , > (
111
- ...refs : Array < MutableRefObject < T > | ForwardedRef < T > >
112
- ) => {
113
- const targetRef = React . useRef < T > ( null ) ;
114
- React . useEffect ( ( ) => {
115
- refs . forEach ( ( ref ) => {
116
- if ( ref ) {
117
- if ( typeof ref === "function" ) {
118
- ref ( targetRef . current ) ;
119
- } else {
120
- ref . current = targetRef . current ;
121
- }
122
- }
123
- } ) ;
124
- } , [ refs ] ) ;
125
- return targetRef ;
126
- } ;
128
+ ) ;
0 commit comments