@shopify/react-native-skia 1.9.0 → 1.10.0
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.
- package/cpp/api/JsiSkCanvas.h +1 -1
- package/lib/commonjs/index.d.ts +1 -1
- package/lib/commonjs/index.js +8 -8
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/renderer/Canvas.d.ts +9 -10
- package/lib/commonjs/renderer/Canvas.js +67 -59
- package/lib/commonjs/renderer/Canvas.js.map +1 -1
- package/lib/commonjs/renderer/CanvasOld.d.ts +11 -0
- package/lib/commonjs/renderer/CanvasOld.js +96 -0
- package/lib/commonjs/renderer/CanvasOld.js.map +1 -0
- package/lib/commonjs/sksg/Container.js +12 -8
- package/lib/commonjs/sksg/Container.js.map +1 -1
- package/lib/commonjs/sksg/HostConfig2.d.ts +19 -0
- package/lib/commonjs/sksg/HostConfig2.js +159 -0
- package/lib/commonjs/sksg/HostConfig2.js.map +1 -0
- package/lib/commonjs/sksg/Recorder/Core.d.ts +42 -37
- package/lib/commonjs/sksg/Recorder/Core.js +46 -38
- package/lib/commonjs/sksg/Recorder/Core.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Player.js +6 -2
- package/lib/commonjs/sksg/Recorder/Player.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Recorder.d.ts +4 -0
- package/lib/commonjs/sksg/Recorder/Recorder.js +14 -2
- package/lib/commonjs/sksg/Recorder/Recorder.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Visitor.js +6 -0
- package/lib/commonjs/sksg/Recorder/Visitor.js.map +1 -1
- package/lib/module/index.d.ts +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/renderer/Canvas.d.ts +9 -10
- package/lib/module/renderer/Canvas.js +65 -55
- package/lib/module/renderer/Canvas.js.map +1 -1
- package/lib/module/renderer/CanvasOld.d.ts +11 -0
- package/lib/module/renderer/CanvasOld.js +87 -0
- package/lib/module/renderer/CanvasOld.js.map +1 -0
- package/lib/module/sksg/Container.js +12 -8
- package/lib/module/sksg/Container.js.map +1 -1
- package/lib/module/sksg/HostConfig2.d.ts +19 -0
- package/lib/module/sksg/HostConfig2.js +152 -0
- package/lib/module/sksg/HostConfig2.js.map +1 -0
- package/lib/module/sksg/Recorder/Core.d.ts +42 -37
- package/lib/module/sksg/Recorder/Core.js +44 -37
- package/lib/module/sksg/Recorder/Core.js.map +1 -1
- package/lib/module/sksg/Recorder/Player.js +7 -3
- package/lib/module/sksg/Recorder/Player.js.map +1 -1
- package/lib/module/sksg/Recorder/Recorder.d.ts +4 -0
- package/lib/module/sksg/Recorder/Recorder.js +14 -2
- package/lib/module/sksg/Recorder/Recorder.js.map +1 -1
- package/lib/module/sksg/Recorder/Visitor.js +6 -0
- package/lib/module/sksg/Recorder/Visitor.js.map +1 -1
- package/lib/typescript/lib/commonjs/renderer/Canvas.d.ts +2 -2
- package/lib/typescript/lib/commonjs/renderer/CanvasOld.d.ts +3 -0
- package/lib/typescript/lib/commonjs/sksg/HostConfig2.d.ts +44 -0
- package/lib/typescript/lib/commonjs/sksg/Recorder/Core.d.ts +1 -0
- package/lib/typescript/lib/commonjs/sksg/Recorder/Recorder.d.ts +2 -0
- package/lib/typescript/lib/module/index.d.ts +1 -1
- package/lib/typescript/lib/module/renderer/Canvas.d.ts +1 -3
- package/lib/typescript/lib/module/renderer/CanvasOld.d.ts +3 -0
- package/lib/typescript/lib/module/sksg/HostConfig2.d.ts +43 -0
- package/lib/typescript/lib/module/sksg/Recorder/Core.d.ts +1 -0
- package/lib/typescript/lib/module/sksg/Recorder/Recorder.d.ts +2 -0
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/renderer/Canvas.d.ts +9 -10
- package/lib/typescript/src/renderer/CanvasOld.d.ts +11 -0
- package/lib/typescript/src/sksg/HostConfig2.d.ts +19 -0
- package/lib/typescript/src/sksg/Recorder/Core.d.ts +42 -37
- package/lib/typescript/src/sksg/Recorder/Recorder.d.ts +4 -0
- package/package.json +3 -2
- package/src/index.ts +1 -1
- package/src/renderer/Canvas.tsx +80 -78
- package/src/renderer/CanvasOld.tsx +126 -0
- package/src/sksg/Container.ts +7 -4
- package/src/sksg/HostConfig2.ts +247 -0
- package/src/sksg/Recorder/Core.ts +11 -0
- package/src/sksg/Recorder/Player.ts +7 -3
- package/src/sksg/Recorder/Recorder.ts +16 -2
- package/src/sksg/Recorder/Visitor.ts +6 -0
- package/lib/commonjs/renderer/Canvas2.d.ts +0 -10
- package/lib/commonjs/renderer/Canvas2.js +0 -104
- package/lib/commonjs/renderer/Canvas2.js.map +0 -1
- package/lib/commonjs/renderer/Canvas2.web.d.ts +0 -3
- package/lib/commonjs/renderer/Canvas2.web.js +0 -9
- package/lib/commonjs/renderer/Canvas2.web.js.map +0 -1
- package/lib/module/renderer/Canvas2.d.ts +0 -10
- package/lib/module/renderer/Canvas2.js +0 -97
- package/lib/module/renderer/Canvas2.js.map +0 -1
- package/lib/module/renderer/Canvas2.web.d.ts +0 -3
- package/lib/module/renderer/Canvas2.web.js +0 -3
- package/lib/module/renderer/Canvas2.web.js.map +0 -1
- package/lib/typescript/lib/commonjs/renderer/Canvas2.d.ts +0 -3
- package/lib/typescript/lib/commonjs/renderer/Canvas2.web.d.ts +0 -2
- package/lib/typescript/lib/module/renderer/Canvas2.d.ts +0 -1
- package/lib/typescript/lib/module/renderer/Canvas2.web.d.ts +0 -1
- package/lib/typescript/src/renderer/Canvas2.d.ts +0 -10
- package/lib/typescript/src/renderer/Canvas2.web.d.ts +0 -3
- package/src/renderer/Canvas2.tsx +0 -128
- package/src/renderer/Canvas2.web.tsx +0 -6
package/src/renderer/Canvas.tsx
CHANGED
|
@@ -1,32 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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,39 +38,40 @@ const useOnSizeEvent = (
|
|
|
46
38
|
);
|
|
47
39
|
};
|
|
48
40
|
|
|
49
|
-
export
|
|
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
|
-
|
|
53
|
-
style,
|
|
51
|
+
mode,
|
|
54
52
|
debug,
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
opaque,
|
|
54
|
+
children,
|
|
55
|
+
onSize,
|
|
57
56
|
onLayout: _onLayout,
|
|
58
|
-
...
|
|
59
|
-
},
|
|
60
|
-
|
|
57
|
+
...viewProps
|
|
58
|
+
}: CanvasProps,
|
|
59
|
+
ref
|
|
61
60
|
) => {
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
}, [
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
[redraw, getNativeId]
|
|
76
|
-
);
|
|
68
|
+
// Root
|
|
69
|
+
const root = useMemo(() => new SkiaSGRoot(Skia, nativeId), [nativeId]);
|
|
77
70
|
|
|
78
|
-
// Render
|
|
71
|
+
// Render effects
|
|
79
72
|
useEffect(() => {
|
|
80
73
|
root.render(children);
|
|
81
|
-
}, [children, root
|
|
74
|
+
}, [children, root]);
|
|
82
75
|
|
|
83
76
|
useEffect(() => {
|
|
84
77
|
return () => {
|
|
@@ -86,41 +79,50 @@ export const Canvas = forwardRef<SkiaDomView, CanvasProps>(
|
|
|
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
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
root={root.dom}
|
|
94
|
-
onLayout={onLayout}
|
|
118
|
+
<NativeSkiaPictureView
|
|
119
|
+
collapsable={false}
|
|
120
|
+
nativeID={`${nativeId}`}
|
|
95
121
|
debug={debug}
|
|
96
|
-
|
|
97
|
-
{
|
|
122
|
+
opaque={opaque}
|
|
123
|
+
onLayout={onLayout}
|
|
124
|
+
{...viewProps}
|
|
98
125
|
/>
|
|
99
126
|
);
|
|
100
127
|
}
|
|
101
|
-
)
|
|
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,0 +1,126 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useEffect,
|
|
3
|
+
useCallback,
|
|
4
|
+
useMemo,
|
|
5
|
+
forwardRef,
|
|
6
|
+
useRef,
|
|
7
|
+
} 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";
|
|
16
|
+
|
|
17
|
+
import { SkiaDomView } from "../views";
|
|
18
|
+
import type { SkiaBaseViewProps } from "../views";
|
|
19
|
+
|
|
20
|
+
import { SkiaRoot } from "./Reconciler";
|
|
21
|
+
|
|
22
|
+
export const useCanvasRef = () => useRef<SkiaDomView>(null);
|
|
23
|
+
|
|
24
|
+
export interface CanvasOldProps extends SkiaBaseViewProps {
|
|
25
|
+
ref?: RefObject<SkiaDomView>;
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
mode?: "default" | "continuous";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const useOnSizeEvent = (
|
|
31
|
+
resultValue: SkiaBaseViewProps["onSize"],
|
|
32
|
+
onLayout?: (event: LayoutChangeEvent) => void
|
|
33
|
+
) => {
|
|
34
|
+
return useCallback(
|
|
35
|
+
(event: LayoutChangeEvent) => {
|
|
36
|
+
if (onLayout) {
|
|
37
|
+
onLayout(event);
|
|
38
|
+
}
|
|
39
|
+
const { width, height } = event.nativeEvent.layout;
|
|
40
|
+
|
|
41
|
+
if (resultValue) {
|
|
42
|
+
resultValue.value = { width, height };
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
[onLayout, resultValue]
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const CanvasOld = forwardRef<SkiaDomView, CanvasOldProps>(
|
|
50
|
+
(
|
|
51
|
+
{
|
|
52
|
+
children,
|
|
53
|
+
style,
|
|
54
|
+
debug,
|
|
55
|
+
mode = "default",
|
|
56
|
+
onSize: _onSize,
|
|
57
|
+
onLayout: _onLayout,
|
|
58
|
+
...props
|
|
59
|
+
},
|
|
60
|
+
forwardedRef
|
|
61
|
+
) => {
|
|
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]);
|
|
72
|
+
|
|
73
|
+
const root = useMemo(
|
|
74
|
+
() => new SkiaRoot(redraw, getNativeId),
|
|
75
|
+
[redraw, getNativeId]
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Render effect
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
root.render(children);
|
|
81
|
+
}, [children, root, redraw]);
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
return () => {
|
|
85
|
+
root.unmount();
|
|
86
|
+
};
|
|
87
|
+
}, [root]);
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<SkiaDomView
|
|
91
|
+
ref={ref}
|
|
92
|
+
style={style}
|
|
93
|
+
root={root.dom}
|
|
94
|
+
onLayout={onLayout}
|
|
95
|
+
debug={debug}
|
|
96
|
+
mode={mode}
|
|
97
|
+
{...props}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
) as FunctionComponent<CanvasOldProps & 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
|
+
};
|
package/src/sksg/Container.ts
CHANGED
|
@@ -14,10 +14,9 @@ const drawOnscreen = (Skia: Skia, nativeId: number, recording: Recording) => {
|
|
|
14
14
|
|
|
15
15
|
const rec = Skia.PictureRecorder();
|
|
16
16
|
const canvas = rec.beginRecording();
|
|
17
|
-
//
|
|
17
|
+
//const start = performance.now();
|
|
18
18
|
|
|
19
19
|
const ctx = createDrawingContext(Skia, recording.paintPool, canvas);
|
|
20
|
-
//console.log(recording.commands);
|
|
21
20
|
replay(ctx, recording.commands);
|
|
22
21
|
const picture = rec.finishRecordingAsPicture();
|
|
23
22
|
//const end = performance.now();
|
|
@@ -42,7 +41,7 @@ export abstract class Container {
|
|
|
42
41
|
this.recording.paintPool,
|
|
43
42
|
canvas
|
|
44
43
|
);
|
|
45
|
-
//console.log(this.
|
|
44
|
+
//console.log(this.recording.commands);
|
|
46
45
|
replay(ctx, this.recording.commands);
|
|
47
46
|
}
|
|
48
47
|
|
|
@@ -88,13 +87,17 @@ class ReanimatedContainer extends Container {
|
|
|
88
87
|
commands: record.commands,
|
|
89
88
|
paintPool: record.paintPool,
|
|
90
89
|
};
|
|
90
|
+
const { nativeId, Skia, recording } = this;
|
|
91
91
|
if (animationValues.size > 0) {
|
|
92
|
-
const { nativeId, Skia, recording } = this;
|
|
93
92
|
this.mapperId = Rea.startMapper(() => {
|
|
94
93
|
"worklet";
|
|
95
94
|
drawOnscreen(Skia, nativeId, recording!);
|
|
96
95
|
}, Array.from(animationValues));
|
|
97
96
|
}
|
|
97
|
+
Rea.runOnUI(() => {
|
|
98
|
+
"worklet";
|
|
99
|
+
drawOnscreen(Skia, nativeId, recording!);
|
|
100
|
+
})();
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
103
|
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/*global NodeJS*/
|
|
2
|
+
import type { Fiber, HostConfig } from "react-reconciler";
|
|
3
|
+
import { DefaultEventPriority } from "react-reconciler/constants";
|
|
4
|
+
|
|
5
|
+
import type { NodeType } from "../dom/types";
|
|
6
|
+
import { shallowEq } from "../renderer/typeddash";
|
|
7
|
+
|
|
8
|
+
import type { Container } from "./Container";
|
|
9
|
+
import type { Node } from "./Node";
|
|
10
|
+
|
|
11
|
+
const DEBUG = false;
|
|
12
|
+
export const debug = (...args: Parameters<typeof console.log>) => {
|
|
13
|
+
if (DEBUG) {
|
|
14
|
+
console.log(...args);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type Instance = Node<unknown>;
|
|
19
|
+
|
|
20
|
+
type Props = object;
|
|
21
|
+
type TextInstance = Node<unknown>;
|
|
22
|
+
type SuspenseInstance = Instance;
|
|
23
|
+
type HydratableInstance = Instance;
|
|
24
|
+
type PublicInstance = Instance;
|
|
25
|
+
type HostContext = null;
|
|
26
|
+
type UpdatePayload = Container;
|
|
27
|
+
type ChildSet = unknown;
|
|
28
|
+
type TimeoutHandle = NodeJS.Timeout;
|
|
29
|
+
type NoTimeout = -1;
|
|
30
|
+
|
|
31
|
+
type SkiaHostConfig = HostConfig<
|
|
32
|
+
NodeType,
|
|
33
|
+
Props,
|
|
34
|
+
Container,
|
|
35
|
+
Instance,
|
|
36
|
+
TextInstance,
|
|
37
|
+
SuspenseInstance,
|
|
38
|
+
HydratableInstance,
|
|
39
|
+
PublicInstance,
|
|
40
|
+
HostContext,
|
|
41
|
+
UpdatePayload,
|
|
42
|
+
ChildSet,
|
|
43
|
+
TimeoutHandle,
|
|
44
|
+
NoTimeout
|
|
45
|
+
>;
|
|
46
|
+
|
|
47
|
+
const appendNode = (parent: Node<unknown>, child: Node<unknown>) => {
|
|
48
|
+
parent.children.push(child);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const removeNode = (parent: Node<unknown>, child: Node<unknown>) => {
|
|
52
|
+
parent.children.splice(parent.children.indexOf(child), 1);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const insertBefore = (
|
|
56
|
+
parent: Node<unknown>,
|
|
57
|
+
child: Node<unknown>,
|
|
58
|
+
before: Node<unknown>
|
|
59
|
+
) => {
|
|
60
|
+
parent.children.splice(parent.children.indexOf(before), 0, child);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const sksgHostConfig: SkiaHostConfig = {
|
|
64
|
+
/**
|
|
65
|
+
* This function is used by the reconciler in order to calculate current time for prioritising work.
|
|
66
|
+
*/
|
|
67
|
+
supportsMutation: true,
|
|
68
|
+
isPrimaryRenderer: false,
|
|
69
|
+
supportsPersistence: false,
|
|
70
|
+
supportsHydration: false,
|
|
71
|
+
//supportsMicrotask: true,
|
|
72
|
+
|
|
73
|
+
scheduleTimeout: setTimeout,
|
|
74
|
+
cancelTimeout: clearTimeout,
|
|
75
|
+
noTimeout: -1,
|
|
76
|
+
|
|
77
|
+
appendChildToContainer(container, child) {
|
|
78
|
+
debug("appendChildToContainer");
|
|
79
|
+
container.root.push(child);
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
appendChild(parent, child) {
|
|
83
|
+
debug("appendChild", parent, child);
|
|
84
|
+
appendNode(parent, child);
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
getRootHostContext: (_rootContainerInstance: Container) => {
|
|
88
|
+
debug("getRootHostContext");
|
|
89
|
+
return null;
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
getChildHostContext(_parentHostContext, _type, _rootContainerInstance) {
|
|
93
|
+
debug("getChildHostContext");
|
|
94
|
+
return null;
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
shouldSetTextContent(_type, _props) {
|
|
98
|
+
return false;
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
createTextInstance(
|
|
102
|
+
_text,
|
|
103
|
+
_rootContainerInstance,
|
|
104
|
+
_hostContext,
|
|
105
|
+
_internalInstanceHandle
|
|
106
|
+
) {
|
|
107
|
+
debug("createTextInstance");
|
|
108
|
+
// return SpanNode({}, text) as SkNode;
|
|
109
|
+
throw new Error("Text nodes are not supported yet");
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
createInstance(
|
|
113
|
+
type,
|
|
114
|
+
propsWithChildren,
|
|
115
|
+
_container,
|
|
116
|
+
_hostContext,
|
|
117
|
+
_internalInstanceHandle
|
|
118
|
+
) {
|
|
119
|
+
debug("createInstance", type);
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
121
|
+
const { children, ...props } = propsWithChildren as any;
|
|
122
|
+
debug("createInstance", type);
|
|
123
|
+
const instance = {
|
|
124
|
+
type,
|
|
125
|
+
props,
|
|
126
|
+
children: [],
|
|
127
|
+
};
|
|
128
|
+
return instance;
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
appendInitialChild(parentInstance, child) {
|
|
132
|
+
debug("appendInitialChild");
|
|
133
|
+
appendNode(parentInstance, child);
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
finalizeInitialChildren(
|
|
137
|
+
parentInstance,
|
|
138
|
+
_type,
|
|
139
|
+
_props,
|
|
140
|
+
_rootContainerInstance,
|
|
141
|
+
_hostContext
|
|
142
|
+
) {
|
|
143
|
+
debug("finalizeInitialChildren", parentInstance);
|
|
144
|
+
return false;
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
commitMount() {
|
|
148
|
+
// if finalizeInitialChildren = true
|
|
149
|
+
debug("commitMount");
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
prepareForCommit(_containerInfo) {
|
|
153
|
+
debug("prepareForCommit");
|
|
154
|
+
return null;
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
resetAfterCommit(container) {
|
|
158
|
+
debug("resetAfterCommit");
|
|
159
|
+
container.redraw();
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
getPublicInstance(node: Instance) {
|
|
163
|
+
debug("getPublicInstance");
|
|
164
|
+
return node;
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
prepareUpdate: (
|
|
168
|
+
_instance,
|
|
169
|
+
type,
|
|
170
|
+
oldProps,
|
|
171
|
+
newProps,
|
|
172
|
+
rootContainerInstance,
|
|
173
|
+
_hostContext
|
|
174
|
+
) => {
|
|
175
|
+
debug("prepareUpdate");
|
|
176
|
+
const propsAreEqual = shallowEq(oldProps, newProps);
|
|
177
|
+
if (propsAreEqual) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
debug("update ", type);
|
|
181
|
+
return rootContainerInstance;
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
commitUpdate(
|
|
185
|
+
instance,
|
|
186
|
+
_updatePayload,
|
|
187
|
+
type,
|
|
188
|
+
prevProps,
|
|
189
|
+
nextProps,
|
|
190
|
+
_internalHandle
|
|
191
|
+
) {
|
|
192
|
+
debug("commitUpdate: ", type);
|
|
193
|
+
if (shallowEq(prevProps, nextProps)) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
197
|
+
const { children, ...props } = nextProps as any;
|
|
198
|
+
instance.props = props;
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
commitTextUpdate: (
|
|
202
|
+
_textInstance: TextInstance,
|
|
203
|
+
_oldText: string,
|
|
204
|
+
_newText: string
|
|
205
|
+
) => {
|
|
206
|
+
// textInstance.instance = newText;
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
clearContainer: (container) => {
|
|
210
|
+
debug("clearContainer");
|
|
211
|
+
container.root = [];
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
preparePortalMount: () => {
|
|
215
|
+
debug("preparePortalMount");
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
removeChild: (parent, child) => {
|
|
219
|
+
removeNode(parent, child);
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
removeChildFromContainer: (container, child) => {
|
|
223
|
+
container.root.splice(container.root.indexOf(child), 1);
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
insertInContainerBefore: (container, child, before) => {
|
|
227
|
+
container.root.splice(container.root.indexOf(before), 0, child);
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
insertBefore: (parent, child, before) => {
|
|
231
|
+
insertBefore(parent, child, before);
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
// see https://github.com/pmndrs/react-three-fiber/pull/2360#discussion_r916356874
|
|
235
|
+
getCurrentEventPriority: () => DefaultEventPriority,
|
|
236
|
+
beforeActiveInstanceBlur: () => {},
|
|
237
|
+
afterActiveInstanceBlur: () => {},
|
|
238
|
+
detachDeletedInstance: () => {},
|
|
239
|
+
|
|
240
|
+
getInstanceFromNode: function (_node): Fiber | null | undefined {
|
|
241
|
+
return null;
|
|
242
|
+
},
|
|
243
|
+
prepareScopeUpdate: function (_scopeInstance, _instance): void {},
|
|
244
|
+
getInstanceFromScope: function (_scopeInstance): Instance | null {
|
|
245
|
+
return null;
|
|
246
|
+
},
|
|
247
|
+
};
|
|
@@ -27,6 +27,7 @@ import type {
|
|
|
27
27
|
|
|
28
28
|
// export enum CommandType {
|
|
29
29
|
// // Context
|
|
30
|
+
// Group = "Group",
|
|
30
31
|
// SavePaint = "SavePaint",
|
|
31
32
|
// RestorePaint = "RestorePaint",
|
|
32
33
|
// SaveCTM = "SaveCTM",
|
|
@@ -68,6 +69,7 @@ import type {
|
|
|
68
69
|
// }
|
|
69
70
|
export enum CommandType {
|
|
70
71
|
// Context
|
|
72
|
+
Group,
|
|
71
73
|
SavePaint,
|
|
72
74
|
RestorePaint,
|
|
73
75
|
SaveCTM,
|
|
@@ -133,6 +135,15 @@ export const isCommand = <T extends CommandType>(
|
|
|
133
135
|
return command.type === type;
|
|
134
136
|
};
|
|
135
137
|
|
|
138
|
+
interface GroupCommand extends Command<CommandType.Group> {
|
|
139
|
+
children: Command[];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const isGroup = (command: Command): command is GroupCommand => {
|
|
143
|
+
"worklet";
|
|
144
|
+
return command.type === CommandType.Group;
|
|
145
|
+
};
|
|
146
|
+
|
|
136
147
|
interface Props {
|
|
137
148
|
[CommandType.DrawImage]: ImageProps;
|
|
138
149
|
[CommandType.DrawCircle]: CircleProps;
|
|
@@ -43,14 +43,18 @@ import {
|
|
|
43
43
|
CommandType,
|
|
44
44
|
isCommand,
|
|
45
45
|
isDrawCommand,
|
|
46
|
+
isGroup,
|
|
46
47
|
materializeProps,
|
|
47
48
|
type Command,
|
|
48
49
|
} from "./Core";
|
|
49
50
|
import type { DrawingContext } from "./DrawingContext";
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
function play(ctx: DrawingContext, command: Command) {
|
|
52
53
|
"worklet";
|
|
53
|
-
|
|
54
|
+
if (isGroup(command)) {
|
|
55
|
+
command.children.forEach((child) => play(ctx, child));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
54
58
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
59
|
materializeProps(command as any);
|
|
56
60
|
if (isCommand(command, CommandType.SaveBackdropFilter)) {
|
|
@@ -150,7 +154,7 @@ const play = (ctx: DrawingContext, command: Command) => {
|
|
|
150
154
|
ctx.paints.pop();
|
|
151
155
|
});
|
|
152
156
|
}
|
|
153
|
-
}
|
|
157
|
+
}
|
|
154
158
|
|
|
155
159
|
export const replay = (ctx: DrawingContext, commands: Command[]) => {
|
|
156
160
|
"worklet";
|
|
@@ -46,8 +46,13 @@ interface AnimationValues {
|
|
|
46
46
|
|
|
47
47
|
export class Recorder {
|
|
48
48
|
commands: Command[] = [];
|
|
49
|
+
cursors: Command[][] = [];
|
|
49
50
|
animationValues: Set<SharedValue<unknown>> = new Set();
|
|
50
51
|
|
|
52
|
+
constructor() {
|
|
53
|
+
this.cursors.push(this.commands);
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
getRecording(): Recording & AnimationValues {
|
|
52
57
|
return {
|
|
53
58
|
commands: this.commands,
|
|
@@ -64,7 +69,6 @@ export class Recorder {
|
|
|
64
69
|
const prop = props[key];
|
|
65
70
|
if (isSharedValue(prop)) {
|
|
66
71
|
this.animationValues.add(prop);
|
|
67
|
-
props[key] = prop.value;
|
|
68
72
|
animatedProps[key] = prop;
|
|
69
73
|
hasAnimatedProps = true;
|
|
70
74
|
}
|
|
@@ -85,7 +89,17 @@ export class Recorder {
|
|
|
85
89
|
command.animatedProps = animatedProps;
|
|
86
90
|
}
|
|
87
91
|
}
|
|
88
|
-
this.
|
|
92
|
+
this.cursors[this.cursors.length - 1].push(command);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
saveGroup() {
|
|
96
|
+
const children: Command[] = [];
|
|
97
|
+
this.add({ type: CommandType.Group, children });
|
|
98
|
+
this.cursors.push(children);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
restoreGroup() {
|
|
102
|
+
this.cursors.pop();
|
|
89
103
|
}
|
|
90
104
|
|
|
91
105
|
savePaint(props: AnimatedProps<PaintProps>) {
|