@shopify/react-native-skia 0.1.143 → 0.1.145

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 (67) hide show
  1. package/cpp/api/JsiSkPaint.h +6 -0
  2. package/lib/commonjs/renderer/Canvas.js +17 -7
  3. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  4. package/lib/commonjs/renderer/DependencyManager.js +144 -36
  5. package/lib/commonjs/renderer/DependencyManager.js.map +1 -1
  6. package/lib/commonjs/renderer/HostConfig.js +1 -1
  7. package/lib/commonjs/renderer/HostConfig.js.map +1 -1
  8. package/lib/commonjs/renderer/components/backdrop/BackdropFilter.js.map +1 -1
  9. package/lib/commonjs/renderer/nodes/Declaration.js +2 -3
  10. package/lib/commonjs/renderer/nodes/Declaration.js.map +1 -1
  11. package/lib/commonjs/renderer/nodes/Drawing.js +3 -7
  12. package/lib/commonjs/renderer/nodes/Drawing.js.map +1 -1
  13. package/lib/commonjs/renderer/nodes/Node.js +9 -7
  14. package/lib/commonjs/renderer/nodes/Node.js.map +1 -1
  15. package/lib/commonjs/renderer/processors/Animations/Animations.js +3 -22
  16. package/lib/commonjs/renderer/processors/Animations/Animations.js.map +1 -1
  17. package/lib/commonjs/skia/types/Paint/Paint.js.map +1 -1
  18. package/lib/commonjs/skia/web/Host.js.map +1 -1
  19. package/lib/commonjs/skia/web/JsiSkPaint.js +4 -0
  20. package/lib/commonjs/skia/web/JsiSkPaint.js.map +1 -1
  21. package/lib/module/renderer/Canvas.js +17 -6
  22. package/lib/module/renderer/Canvas.js.map +1 -1
  23. package/lib/module/renderer/DependencyManager.js +140 -33
  24. package/lib/module/renderer/DependencyManager.js.map +1 -1
  25. package/lib/module/renderer/HostConfig.js +1 -1
  26. package/lib/module/renderer/HostConfig.js.map +1 -1
  27. package/lib/module/renderer/components/backdrop/BackdropFilter.js.map +1 -1
  28. package/lib/module/renderer/nodes/Declaration.js +3 -4
  29. package/lib/module/renderer/nodes/Declaration.js.map +1 -1
  30. package/lib/module/renderer/nodes/Drawing.js +3 -6
  31. package/lib/module/renderer/nodes/Drawing.js.map +1 -1
  32. package/lib/module/renderer/nodes/Node.js +9 -7
  33. package/lib/module/renderer/nodes/Node.js.map +1 -1
  34. package/lib/module/renderer/processors/Animations/Animations.js +1 -16
  35. package/lib/module/renderer/processors/Animations/Animations.js.map +1 -1
  36. package/lib/module/skia/types/Paint/Paint.js.map +1 -1
  37. package/lib/module/skia/web/Host.js.map +1 -1
  38. package/lib/module/skia/web/JsiSkPaint.js +4 -0
  39. package/lib/module/skia/web/JsiSkPaint.js.map +1 -1
  40. package/lib/typescript/src/renderer/Canvas.d.ts +1 -1
  41. package/lib/typescript/src/renderer/DependencyManager.d.ts +40 -14
  42. package/lib/typescript/src/renderer/nodes/Declaration.d.ts +2 -2
  43. package/lib/typescript/src/renderer/nodes/Drawing.d.ts +2 -2
  44. package/lib/typescript/src/renderer/nodes/Node.d.ts +3 -2
  45. package/lib/typescript/src/renderer/processors/Animations/Animations.d.ts +0 -1
  46. package/lib/typescript/src/skia/types/Paint/Paint.d.ts +5 -0
  47. package/lib/typescript/src/skia/web/Host.d.ts +1 -1
  48. package/lib/typescript/src/skia/web/JsiSkPaint.d.ts +1 -0
  49. package/libs/ios/libskia.xcframework/Info.plist +5 -5
  50. package/libs/ios/libskia.xcframework/ios-arm64_arm64e/libskia.a +0 -0
  51. package/libs/ios/libskia.xcframework/ios-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  52. package/libs/ios/libskshaper.xcframework/ios-arm64_arm64e/libskshaper.a +0 -0
  53. package/libs/ios/libskshaper.xcframework/ios-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  54. package/libs/ios/libsvg.xcframework/ios-arm64_arm64e/libsvg.a +0 -0
  55. package/libs/ios/libsvg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  56. package/package.json +1 -1
  57. package/src/renderer/Canvas.tsx +19 -7
  58. package/src/renderer/DependencyManager.tsx +170 -39
  59. package/src/renderer/HostConfig.ts +1 -1
  60. package/src/renderer/components/backdrop/BackdropFilter.tsx +1 -1
  61. package/src/renderer/nodes/Declaration.tsx +6 -8
  62. package/src/renderer/nodes/Drawing.tsx +5 -7
  63. package/src/renderer/nodes/Node.ts +11 -9
  64. package/src/renderer/processors/Animations/Animations.ts +2 -15
  65. package/src/skia/types/Paint/Paint.ts +6 -0
  66. package/src/skia/web/Host.ts +1 -1
  67. package/src/skia/web/JsiSkPaint.ts +4 -0
@@ -20,6 +20,7 @@ import { SkiaView, useDrawCallback } from "../views";
20
20
  import type { TouchHandler } from "../views";
21
21
  import { useValue } from "../values/hooks/useValue";
22
22
  import { Skia } from "../skia/Skia";
23
+ import type { SkiaValue } from "../values";
23
24
 
24
25
  import { debug as hostDebug, skHostConfig } from "./HostConfig";
25
26
  // import { debugTree } from "./nodes";
@@ -38,8 +39,7 @@ skiaReconciler.injectIntoDevTools({
38
39
  const render = (element: ReactNode, root: OpaqueRoot, container: Container) => {
39
40
  skiaReconciler.updateContainer(element, root, null, () => {
40
41
  hostDebug("updateContainer");
41
-
42
- container.depMgr.subscribe();
42
+ container.depMgr.update();
43
43
  });
44
44
  };
45
45
 
@@ -60,9 +60,19 @@ export const Canvas = forwardRef<SkiaView, CanvasProps>(
60
60
  const [tick, setTick] = useState(0);
61
61
  const redraw = useCallback(() => setTick((t) => t + 1), []);
62
62
 
63
+ const registerValues = useCallback(
64
+ (values: Array<SkiaValue<unknown>>) => {
65
+ if (ref.current === null) {
66
+ throw new Error("Canvas ref is not set");
67
+ }
68
+ return ref.current.registerValues(values);
69
+ },
70
+ [ref]
71
+ );
72
+
63
73
  const container = useMemo(
64
- () => new Container(new DependencyManager(ref), redraw),
65
- [redraw, ref]
74
+ () => new Container(new DependencyManager(registerValues), redraw),
75
+ [redraw, registerValues]
66
76
  );
67
77
 
68
78
  const root = useMemo(
@@ -78,6 +88,8 @@ export const Canvas = forwardRef<SkiaView, CanvasProps>(
78
88
  );
79
89
  }, [children, root, redraw, container, canvasCtx]);
80
90
 
91
+ const paint = useMemo(() => Skia.Paint(), []);
92
+
81
93
  // Draw callback
82
94
  const onDraw = useDrawCallback(
83
95
  (canvas, info) => {
@@ -92,7 +104,7 @@ export const Canvas = forwardRef<SkiaView, CanvasProps>(
92
104
  ) {
93
105
  canvasCtx.size.current = { width, height };
94
106
  }
95
- const paint = Skia.Paint();
107
+ paint.reset();
96
108
  const ctx = {
97
109
  width,
98
110
  height,
@@ -101,7 +113,7 @@ export const Canvas = forwardRef<SkiaView, CanvasProps>(
101
113
  paint,
102
114
  opacity: 1,
103
115
  ref,
104
- center: Skia.Point(width / 2, height / 2),
116
+ center: { x: width / 2, y: height / 2 },
105
117
  Skia,
106
118
  };
107
119
  container.draw(ctx);
@@ -112,7 +124,7 @@ export const Canvas = forwardRef<SkiaView, CanvasProps>(
112
124
  useEffect(() => {
113
125
  return () => {
114
126
  skiaReconciler.updateContainer(null, root, null, () => {
115
- container.depMgr.unsubscribe();
127
+ container.depMgr.remove();
116
128
  });
117
129
  };
118
130
  }, [container, root]);
@@ -1,62 +1,193 @@
1
- import type { RefObject } from "react";
2
-
3
- import type { SkiaView } from "../views";
4
1
  import type { SkiaValue } from "../values";
5
2
 
6
- import { isSelector, isValue } from "./processors";
7
3
  import type { Node } from "./nodes";
4
+ import type { AnimatedProps } from "./processors";
5
+ import { isSelector, isValue } from "./processors";
6
+ import { mapKeys } from "./typeddash";
8
7
 
9
8
  type Unsubscribe = () => void;
10
- type Props = { [key: string]: unknown };
9
+ type Mutator = (value: unknown) => void;
10
+
11
+ type SubscriptionState = {
12
+ nodes: Map<Node, Mutator[]>;
13
+ unsubscribe: null | Unsubscribe;
14
+ };
11
15
 
12
16
  export class DependencyManager {
13
- ref: RefObject<SkiaView>;
14
- subscriptions: Map<
15
- Node,
16
- { values: SkiaValue<unknown>[]; unsubscribe: null | Unsubscribe }
17
- > = new Map();
18
-
19
- constructor(ref: RefObject<SkiaView>) {
20
- this.ref = ref;
21
- }
17
+ registerValues: (values: Array<SkiaValue<unknown>>) => () => void;
18
+ subscriptions: Map<SkiaValue<unknown>, SubscriptionState> = new Map();
19
+ unregisterDependantValues: null | Unsubscribe = null;
22
20
 
23
- unSubscribeNode(node: Node) {
24
- const subscription = this.subscriptions.get(node);
25
- if (subscription && subscription.unsubscribe) {
26
- subscription.unsubscribe();
27
- }
28
- this.subscriptions.delete(node);
21
+ constructor(
22
+ registerValues: (values: Array<SkiaValue<unknown>>) => () => void
23
+ ) {
24
+ this.registerValues = registerValues;
29
25
  }
30
26
 
31
- subscribeNode(node: Node, props: Props) {
32
- const values = Object.values(props)
33
- .filter((v) => isValue(v) || isSelector(v))
34
- .map((v) => (isSelector(v) ? v.value : (v as SkiaValue<unknown>)));
27
+ /**
28
+ * Call to unsubscribe all value listeners from the given node based
29
+ * on the current list of subscriptions for the node. This function
30
+ * is typically called when the node is unmounted or when one or more
31
+ * properties have changed.
32
+ * @param node Node to unsubscribe value listeners from
33
+ */
34
+ unsubscribeNode(node: Node) {
35
+ const subscriptions = Array.from(this.subscriptions.values()).filter((p) =>
36
+ p.nodes.has(node)
37
+ );
35
38
 
36
- if (values.length > 0) {
37
- this.subscriptions.set(node, { values, unsubscribe: null });
39
+ if (subscriptions) {
40
+ subscriptions.forEach((si) => {
41
+ // Delete node from subscription
42
+ si.nodes.delete(node);
43
+
44
+ // Remove subscription if there are no listeneres left on the value
45
+ if (si.nodes.size === 0) {
46
+ // There are no more nodes subscribing to this value, we can call
47
+ // unsubscribe on it.
48
+ if (!si.unsubscribe) {
49
+ throw new Error("Failed to unsubscribe to value subscription");
50
+ }
51
+ si.unsubscribe && si.unsubscribe();
52
+
53
+ // Remove from subscription states as well
54
+ const element = Array.from(this.subscriptions.entries()).find(
55
+ ([_, sub]) => sub === si
56
+ );
57
+ if (!element) {
58
+ throw new Error("Failed to find value subscription");
59
+ }
60
+ if (!this.subscriptions.delete(element[0])) {
61
+ throw new Error("Failed to delete value subscription");
62
+ }
63
+ }
64
+ });
38
65
  }
39
66
  }
40
67
 
41
- subscribe() {
42
- if (this.ref.current === null) {
43
- throw new Error("Canvas ref is not set");
68
+ /**
69
+ * Adds listeners to the provided values so that the node is notified
70
+ * when a value changes. This is done in an optimized way so that this
71
+ * class only needs to listen to the value once and then forwards the
72
+ * change to the node and its listener. This method is typically called
73
+ * when the node is mounted and when one or more props on the node changes.
74
+ * @param node Node to subscribe to value changes for
75
+ * @param props Node's properties
76
+ * @param onResolveProp Callback when a property value changes
77
+ */
78
+ subscribeNode<P extends Record<string, unknown>>(
79
+ node: Node,
80
+ props: AnimatedProps<P>
81
+ ) {
82
+ // Get mutators from node's properties
83
+ const propSubscriptions = initializePropertySubscriptions(node, props);
84
+ if (propSubscriptions.length === 0) {
85
+ return;
44
86
  }
45
- this.subscriptions.forEach((subscription) => {
46
- if (subscription.unsubscribe === null) {
47
- subscription.unsubscribe = this.ref.current!.registerValues(
48
- subscription.values
49
- );
87
+
88
+ // Install all mutators for the node
89
+ propSubscriptions.forEach((ps) => {
90
+ // Do we already have a state for this SkiaValue
91
+ let subscriptionState = this.subscriptions.get(ps.value);
92
+ if (!subscriptionState) {
93
+ // Let's create a new subscription state for the skia value
94
+ subscriptionState = {
95
+ nodes: new Map(),
96
+ unsubscribe: null,
97
+ };
98
+ // Add single subscription to the new value
99
+ subscriptionState.unsubscribe = ps.value.addListener((v) => {
100
+ subscriptionState!.nodes.forEach((mutators) =>
101
+ mutators.forEach((m) => m(v))
102
+ );
103
+ });
104
+ this.subscriptions.set(ps.value, subscriptionState);
50
105
  }
106
+ // subscription mutators
107
+ subscriptionState.nodes.set(
108
+ node,
109
+ propSubscriptions
110
+ .filter((m) => m.value === ps.value)
111
+ .map((m) => m.mutator)
112
+ );
51
113
  });
52
114
  }
53
115
 
54
- unsubscribe() {
55
- this.subscriptions.forEach(({ unsubscribe }) => {
56
- if (unsubscribe) {
57
- unsubscribe();
58
- }
116
+ /**
117
+ * Called when the hosting container is mounted or updated. This ensures that we have
118
+ * a ref to the underlying SkiaView so that we can registers redraw listeners
119
+ * on values used in the current View automatically.
120
+ */
121
+ update() {
122
+ // Remove any previous registrations
123
+ if (this.unregisterDependantValues) {
124
+ this.unregisterDependantValues();
125
+ }
126
+
127
+ // Register redraw requests on the SkiaView for each unique value
128
+ this.unregisterDependantValues = this.registerValues(
129
+ Array.from(this.subscriptions.keys())
130
+ );
131
+ }
132
+
133
+ /**
134
+ * Called when the hosting container is unmounted or recreated. This ensures that we remove
135
+ * all subscriptions to Skia values so that we don't have any listeners left after
136
+ * the component is removed.
137
+ */
138
+ remove() {
139
+ // 1) Unregister redraw requests
140
+ if (this.unregisterDependantValues) {
141
+ this.unregisterDependantValues();
142
+ this.unregisterDependantValues = null;
143
+ }
144
+
145
+ // 2) Unregister nodes
146
+ Array.from(this.subscriptions.values()).forEach((si) => {
147
+ Array.from(si.nodes.keys()).forEach((node) => this.unsubscribeNode(node));
59
148
  });
149
+
150
+ // 3) Clear the rest of the subscriptions
60
151
  this.subscriptions.clear();
61
152
  }
62
153
  }
154
+
155
+ const initializePropertySubscriptions = <P,>(
156
+ node: Node<P>,
157
+ props: AnimatedProps<P>
158
+ ) => {
159
+ const nodePropSubscriptions: Array<{
160
+ value: SkiaValue<unknown>;
161
+ mutator: Mutator;
162
+ }> = [];
163
+
164
+ mapKeys(props).forEach((key) => {
165
+ const propvalue = props[key];
166
+
167
+ if (isValue(propvalue)) {
168
+ // Subscribe to changes
169
+ nodePropSubscriptions.push({
170
+ value: propvalue,
171
+ mutator: (v) => (node.resolvedProps[key] = v as P[typeof key]),
172
+ });
173
+ // Set initial value
174
+ node.resolvedProps[key] = (propvalue as SkiaValue<P[typeof key]>).current;
175
+ } else if (isSelector(propvalue)) {
176
+ // Subscribe to changes
177
+ nodePropSubscriptions.push({
178
+ value: propvalue.value,
179
+ mutator: (v) =>
180
+ (node.resolvedProps[key] = propvalue.selector(v) as P[typeof key]),
181
+ });
182
+ // Set initial value
183
+ node.resolvedProps[key] = propvalue.selector(
184
+ propvalue.value.current
185
+ ) as P[typeof key];
186
+ } else {
187
+ // Set initial value
188
+ node.resolvedProps[key] = propvalue as P[typeof key];
189
+ }
190
+ });
191
+
192
+ return nodePropSubscriptions;
193
+ };
@@ -101,7 +101,7 @@ const removeNode = (parent: Node, child: Node) => {
101
101
  bustBranchMemoization(parent);
102
102
  const index = parent.children.indexOf(child);
103
103
  parent.children.splice(index, 1);
104
- child.depMgr.unSubscribeNode(child);
104
+ child.depMgr.unsubscribeNode(child);
105
105
  // unsubscribe to all children as well
106
106
  for (const c of child.children) {
107
107
  removeNode(child, c);
@@ -8,7 +8,7 @@ import { getInput } from "../imageFilters/getInput";
8
8
  import type { GroupProps } from "../Group";
9
9
  import { Group } from "../Group";
10
10
 
11
- const disableFilterMemoization = (children: Node<unknown>[]) => {
11
+ const disableFilterMemoization = (children: Node[]) => {
12
12
  children.forEach((child) => {
13
13
  child.memoizable = false;
14
14
  disableFilterMemoization(child.children);
@@ -3,7 +3,7 @@ import { useCallback } from "react";
3
3
 
4
4
  import type { DrawingContext } from "../DrawingContext";
5
5
  import type { AnimatedProps } from "../processors";
6
- import { isAnimated, materialize } from "../processors";
6
+ import { isAnimated } from "../processors";
7
7
  import type { DependencyManager } from "../DependencyManager";
8
8
  import type { SkJSIInstance } from "../../skia/types";
9
9
 
@@ -28,9 +28,8 @@ export const useDeclaration = <P,>(
28
28
  // eslint-disable-next-line react-hooks/exhaustive-deps
29
29
  useCallback(cb, deps ?? []);
30
30
 
31
- export const isDeclarationNode = (
32
- node: Node
33
- ): node is DeclarationNode<unknown> => node instanceof DeclarationNode;
31
+ export const isDeclarationNode = <P,>(node: Node): node is DeclarationNode<P> =>
32
+ node instanceof DeclarationNode;
34
33
 
35
34
  export interface DeclarationProps<P> {
36
35
  onDeclare: DeclarationCallback<P>;
@@ -54,14 +53,13 @@ export class DeclarationNode<P> extends Node<P> {
54
53
  super.props = props;
55
54
  }
56
55
 
57
- get props() {
58
- return this._props;
56
+ get props(): P {
57
+ return this.resolvedProps;
59
58
  }
60
59
 
61
60
  draw(ctx: DrawingContext) {
62
61
  const children = this.visit(ctx);
63
- const props = materialize(this.props);
64
- const obj = this.onDeclare(props, children, ctx);
62
+ const obj = this.onDeclare(this.props, children, ctx);
65
63
  return obj;
66
64
  }
67
65
  }
@@ -3,7 +3,6 @@ import { useCallback } from "react";
3
3
 
4
4
  import type { DrawingContext } from "../DrawingContext";
5
5
  import type { AnimatedProps } from "../processors/Animations/Animations";
6
- import { materialize } from "../processors/Animations/Animations";
7
6
  import { isPaint } from "../../skia/types";
8
7
  import type { DependencyManager } from "../DependencyManager";
9
8
  import { processPaint } from "../processors";
@@ -25,8 +24,8 @@ export const useDrawing = <P,>(cb: OnDrawCallback<P>, deps?: DependencyList) =>
25
24
  // eslint-disable-next-line react-hooks/exhaustive-deps
26
25
  useCallback(cb, deps ?? []);
27
26
 
28
- export type DrawingProps<T> = {
29
- onDraw: DrawingCallback<T>;
27
+ export type DrawingProps<P> = {
28
+ onDraw: DrawingCallback<P>;
30
29
  skipProcessing?: boolean;
31
30
  children?: ReactNode | ReactNode[];
32
31
  };
@@ -47,20 +46,19 @@ export class DrawingNode<P> extends Node<P> {
47
46
  }
48
47
 
49
48
  draw(ctx: DrawingContext) {
50
- const drawingProps = materialize(this.props);
51
49
  if (this.skipProcessing) {
52
- this.onDraw(ctx, drawingProps, this);
50
+ this.onDraw(ctx, this.props, this);
53
51
  } else {
54
52
  const declarations = this.visit(ctx);
55
53
  const paint = processPaint(
56
54
  ctx.Skia,
57
55
  ctx.paint.copy(),
58
56
  ctx.opacity,
59
- drawingProps,
57
+ this.props,
60
58
  declarations
61
59
  );
62
60
  [paint, ...declarations.filter(isPaint)].forEach((currentPaint) => {
63
- this.onDraw({ ...ctx, paint: currentPaint }, drawingProps, this);
61
+ this.onDraw({ ...ctx, paint: currentPaint }, this.props, this);
64
62
  });
65
63
  }
66
64
  }
@@ -12,29 +12,31 @@ type DeclarationResult = SkJSIInstance<string> | null;
12
12
 
13
13
  export abstract class Node<P = unknown> {
14
14
  readonly children: Node[] = [];
15
- _props: AnimatedProps<P>;
15
+ // This cast is ok because we understand that the dependency manager will setup the initial props
16
+ resolvedProps: P = {} as P;
16
17
  memoizable = false;
17
18
  memoized: DeclarationResult | null = null;
18
19
  parent?: Node;
19
20
  depMgr: DependencyManager;
20
21
 
21
22
  constructor(depMgr: DependencyManager, props: AnimatedProps<P>) {
22
- this._props = props;
23
23
  this.depMgr = depMgr;
24
- this.depMgr.unSubscribeNode(this);
25
- this.depMgr.subscribeNode(this, props);
24
+ this.updatePropSubscriptions(props);
26
25
  }
27
26
 
28
27
  abstract draw(ctx: DrawingContext): void | DeclarationResult;
29
28
 
30
- set props(props: AnimatedProps<P>) {
31
- this.depMgr.unSubscribeNode(this);
29
+ updatePropSubscriptions(props: AnimatedProps<P>) {
32
30
  this.depMgr.subscribeNode(this, props);
33
- this._props = props;
34
31
  }
35
32
 
36
- get props() {
37
- return this._props;
33
+ set props(props: AnimatedProps<P>) {
34
+ this.depMgr.unsubscribeNode(this);
35
+ this.updatePropSubscriptions(props);
36
+ }
37
+
38
+ get props(): P {
39
+ return this.resolvedProps;
38
40
  }
39
41
 
40
42
  visit(ctx: DrawingContext, children?: Node[]) {
@@ -1,5 +1,4 @@
1
1
  import type { SkiaSelector, SkiaValue } from "../../../values";
2
- import { mapKeys } from "../../typeddash";
3
2
 
4
3
  export const isValue = (value: unknown): value is SkiaValue<unknown> => {
5
4
  if (value === undefined || value === null) {
@@ -37,28 +36,16 @@ export const isSelector = <T, R>(
37
36
 
38
37
  export const isAnimated = <T>(props: AnimatedProps<T>) => {
39
38
  for (const value of Object.values(props)) {
40
- if (isValue(value)) {
39
+ if (isValue(value) || isSelector(value)) {
41
40
  return true;
42
41
  }
43
42
  }
44
43
  return false;
45
44
  };
46
45
 
47
- export const materialize = <T>(props: AnimatedProps<T>) => {
48
- const result = { ...props };
49
- mapKeys(props).forEach((key) => {
50
- const prop = props[key];
51
- if (isValue(prop)) {
52
- result[key] = (prop as SkiaValue<T[typeof key]>).current;
53
- } else if (isSelector(prop)) {
54
- result[key] = prop.selector(prop.value.current) as T[typeof key];
55
- }
56
- });
57
- return result as T;
58
- };
59
-
60
46
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
47
  export type AnimatedProp<T, P = any> = T | SkiaValue<T> | SkiaSelector<T, P>;
48
+
62
49
  export type AnimatedProps<T> = {
63
50
  [K in keyof T]: AnimatedProp<T[K]>;
64
51
  };
@@ -34,6 +34,12 @@ export interface SkPaint extends SkJSIInstance<"Paint"> {
34
34
  */
35
35
  copy(): SkPaint;
36
36
 
37
+ /**
38
+ * Sets all SkPaint contents to their initial values. This is equivalent to replacing
39
+ SkPaint with the result of SkPaint().
40
+ */
41
+ reset(): void;
42
+
37
43
  /**
38
44
  * Retrieves the alpha and RGB unpremultiplied. RGB are extended sRGB values
39
45
  * (sRGB gamut, and encoded with the sRGB transfer function).
@@ -21,7 +21,7 @@ export abstract class BaseHostObject<T, N extends string>
21
21
  implements SkJSIInstance<N>
22
22
  {
23
23
  readonly __typename__: N;
24
- readonly ref: T;
24
+ ref: T;
25
25
 
26
26
  constructor(CanvasKit: CanvasKit, ref: T, typename: N) {
27
27
  super(CanvasKit);
@@ -30,6 +30,10 @@ export class JsiSkPaint extends HostObject<Paint, "Paint"> implements SkPaint {
30
30
  return new JsiSkPaint(this.CanvasKit, this.ref.copy());
31
31
  }
32
32
 
33
+ reset() {
34
+ this.ref = new this.CanvasKit.Paint();
35
+ }
36
+
33
37
  getColor() {
34
38
  return this.ref.getColor();
35
39
  }