@shopify/react-native-skia 0.1.141 → 0.1.142

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 (114) hide show
  1. package/android/cpp/rnskia-android/RNSkDrawViewImpl.cpp +2 -2
  2. package/android/cpp/rnskia-android/RNSkDrawViewImpl.h +1 -1
  3. package/android/cpp/rnskia-android/SkiaOpenGLRenderer.cpp +15 -16
  4. package/android/cpp/rnskia-android/SkiaOpenGLRenderer.h +2 -2
  5. package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java +69 -27
  6. package/cpp/rnskia/RNSkDrawView.cpp +66 -66
  7. package/cpp/rnskia/RNSkDrawView.h +22 -6
  8. package/cpp/rnskia/RNSkJsiViewApi.h +2 -2
  9. package/cpp/rnskia/values/RNSkComputedValue.h +10 -7
  10. package/cpp/rnskia/values/RNSkReadonlyValue.h +21 -2
  11. package/cpp/rnskia/values/RNSkValue.h +1 -0
  12. package/ios/RNSkia-iOS/RNSkDrawViewImpl.h +1 -1
  13. package/ios/RNSkia-iOS/RNSkDrawViewImpl.mm +2 -2
  14. package/ios/RNSkia-iOS/SkiaDrawView.mm +4 -0
  15. package/lib/commonjs/mock/index.js +3 -1
  16. package/lib/commonjs/mock/index.js.map +1 -1
  17. package/lib/commonjs/renderer/DependencyManager.js +1 -1
  18. package/lib/commonjs/renderer/DependencyManager.js.map +1 -1
  19. package/lib/commonjs/renderer/processors/Animations/Animations.js +18 -5
  20. package/lib/commonjs/renderer/processors/Animations/Animations.js.map +1 -1
  21. package/lib/commonjs/skia/core/Data.js +10 -22
  22. package/lib/commonjs/skia/core/Data.js.map +1 -1
  23. package/lib/commonjs/skia/core/Font.js +2 -3
  24. package/lib/commonjs/skia/core/Font.js.map +1 -1
  25. package/lib/commonjs/skia/core/Image.js.map +1 -1
  26. package/lib/commonjs/skia/core/SVG.js.map +1 -1
  27. package/lib/commonjs/skia/core/Typeface.js.map +1 -1
  28. package/lib/commonjs/skia/types/Data/Data.js +5 -0
  29. package/lib/commonjs/skia/types/Data/Data.js.map +1 -1
  30. package/lib/commonjs/skia/web/JsiSkCanvas.js +9 -7
  31. package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
  32. package/lib/commonjs/skia/web/JsiSkPath.js +7 -5
  33. package/lib/commonjs/skia/web/JsiSkPath.js.map +1 -1
  34. package/lib/commonjs/skia/web/JsiSkRRect.js +8 -0
  35. package/lib/commonjs/skia/web/JsiSkRRect.js.map +1 -1
  36. package/lib/commonjs/skia/web/JsiSkRect.js +2 -2
  37. package/lib/commonjs/skia/web/JsiSkRect.js.map +1 -1
  38. package/lib/commonjs/values/hooks/useComputedValue.js +6 -2
  39. package/lib/commonjs/values/hooks/useComputedValue.js.map +1 -1
  40. package/lib/commonjs/values/index.js +13 -0
  41. package/lib/commonjs/values/index.js.map +1 -1
  42. package/lib/commonjs/values/selector.js +24 -0
  43. package/lib/commonjs/values/selector.js.map +1 -0
  44. package/lib/commonjs/values/web/RNSkComputedValue.js +8 -0
  45. package/lib/commonjs/values/web/RNSkComputedValue.js.map +1 -1
  46. package/lib/commonjs/values/web/RNSkReadonlyValue.js +4 -0
  47. package/lib/commonjs/values/web/RNSkReadonlyValue.js.map +1 -1
  48. package/lib/module/mock/index.js +2 -1
  49. package/lib/module/mock/index.js.map +1 -1
  50. package/lib/module/renderer/DependencyManager.js +2 -2
  51. package/lib/module/renderer/DependencyManager.js.map +1 -1
  52. package/lib/module/renderer/processors/Animations/Animations.js +13 -4
  53. package/lib/module/renderer/processors/Animations/Animations.js.map +1 -1
  54. package/lib/module/skia/core/Data.js +10 -20
  55. package/lib/module/skia/core/Data.js.map +1 -1
  56. package/lib/module/skia/core/Font.js +2 -3
  57. package/lib/module/skia/core/Font.js.map +1 -1
  58. package/lib/module/skia/core/Image.js.map +1 -1
  59. package/lib/module/skia/core/SVG.js.map +1 -1
  60. package/lib/module/skia/core/Typeface.js.map +1 -1
  61. package/lib/module/skia/types/Data/Data.js +1 -1
  62. package/lib/module/skia/types/Data/Data.js.map +1 -1
  63. package/lib/module/skia/web/JsiSkCanvas.js +8 -7
  64. package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
  65. package/lib/module/skia/web/JsiSkPath.js +6 -5
  66. package/lib/module/skia/web/JsiSkPath.js.map +1 -1
  67. package/lib/module/skia/web/JsiSkRRect.js +8 -0
  68. package/lib/module/skia/web/JsiSkRRect.js.map +1 -1
  69. package/lib/module/skia/web/JsiSkRect.js +2 -2
  70. package/lib/module/skia/web/JsiSkRect.js.map +1 -1
  71. package/lib/module/values/hooks/useComputedValue.js +7 -3
  72. package/lib/module/values/hooks/useComputedValue.js.map +1 -1
  73. package/lib/module/values/index.js +1 -0
  74. package/lib/module/values/index.js.map +1 -1
  75. package/lib/module/values/selector.js +15 -0
  76. package/lib/module/values/selector.js.map +1 -0
  77. package/lib/module/values/web/RNSkComputedValue.js +8 -0
  78. package/lib/module/values/web/RNSkComputedValue.js.map +1 -1
  79. package/lib/module/values/web/RNSkReadonlyValue.js +4 -0
  80. package/lib/module/values/web/RNSkReadonlyValue.js.map +1 -1
  81. package/lib/typescript/src/renderer/processors/Animations/Animations.d.ts +7 -2
  82. package/lib/typescript/src/skia/core/Data.d.ts +3 -5
  83. package/lib/typescript/src/skia/core/Font.d.ts +2 -2
  84. package/lib/typescript/src/skia/core/Image.d.ts +2 -2
  85. package/lib/typescript/src/skia/core/SVG.d.ts +2 -2
  86. package/lib/typescript/src/skia/core/Typeface.d.ts +2 -2
  87. package/lib/typescript/src/skia/types/Data/Data.d.ts +10 -3
  88. package/lib/typescript/src/skia/web/JsiSkRRect.d.ts +1 -0
  89. package/lib/typescript/src/skia/web/JsiSkRect.d.ts +1 -1
  90. package/lib/typescript/src/values/index.d.ts +1 -0
  91. package/lib/typescript/src/values/selector.d.ts +14 -0
  92. package/lib/typescript/src/values/types.d.ts +4 -0
  93. package/lib/typescript/src/values/web/RNSkComputedValue.d.ts +1 -0
  94. package/lib/typescript/src/values/web/RNSkReadonlyValue.d.ts +1 -0
  95. package/package.json +2 -2
  96. package/src/mock/index.ts +2 -1
  97. package/src/renderer/DependencyManager.tsx +5 -2
  98. package/src/renderer/processors/Animations/Animations.ts +27 -5
  99. package/src/skia/core/Data.ts +20 -51
  100. package/src/skia/core/Font.ts +4 -5
  101. package/src/skia/core/Image.ts +2 -2
  102. package/src/skia/core/SVG.ts +2 -2
  103. package/src/skia/core/Typeface.ts +2 -2
  104. package/src/skia/types/Data/Data.ts +11 -1
  105. package/src/skia/web/JsiSkCanvas.ts +22 -10
  106. package/src/skia/web/JsiSkPath.ts +14 -5
  107. package/src/skia/web/JsiSkRRect.ts +11 -0
  108. package/src/skia/web/JsiSkRect.ts +2 -5
  109. package/src/values/hooks/useComputedValue.ts +6 -3
  110. package/src/values/index.ts +1 -0
  111. package/src/values/selector.ts +24 -0
  112. package/src/values/types.ts +4 -0
  113. package/src/values/web/RNSkComputedValue.ts +6 -0
  114. package/src/values/web/RNSkReadonlyValue.ts +4 -0
@@ -3,7 +3,7 @@ import type { RefObject } from "react";
3
3
  import type { SkiaView } from "../views";
4
4
  import type { SkiaValue } from "../values";
5
5
 
6
- import { isValue } from "./processors";
6
+ import { isSelector, isValue } from "./processors";
7
7
  import type { Node } from "./nodes";
8
8
 
9
9
  type Unsubscribe = () => void;
@@ -29,7 +29,10 @@ export class DependencyManager {
29
29
  }
30
30
 
31
31
  subscribeNode(node: Node, props: Props) {
32
- const values = Object.values(props).filter(isValue);
32
+ const values = Object.values(props)
33
+ .filter((v) => isValue(v) || isSelector(v))
34
+ .map((v) => (isSelector(v) ? v.value : (v as SkiaValue<unknown>)));
35
+
33
36
  if (values.length > 0) {
34
37
  this.subscriptions.set(node, { values, unsubscribe: null });
35
38
  }
@@ -1,4 +1,4 @@
1
- import type { SkiaValue } from "../../../values";
1
+ import type { SkiaSelector, SkiaValue } from "../../../values";
2
2
  import { mapKeys } from "../../typeddash";
3
3
 
4
4
  export const isValue = (value: unknown): value is SkiaValue<unknown> => {
@@ -17,6 +17,24 @@ export const isValue = (value: unknown): value is SkiaValue<unknown> => {
17
17
  return false;
18
18
  };
19
19
 
20
+ export const isSelector = <T, R>(
21
+ value: unknown
22
+ ): value is {
23
+ selector: (v: T) => R;
24
+ value: SkiaValue<T>;
25
+ } => {
26
+ if (value) {
27
+ return (
28
+ typeof value === "object" &&
29
+ "selector" in value &&
30
+ "value" in value &&
31
+ (value as Record<string, unknown>).selector !== undefined &&
32
+ (value as Record<string, unknown>).value !== undefined
33
+ );
34
+ }
35
+ return false;
36
+ };
37
+
20
38
  export const isAnimated = <T>(props: AnimatedProps<T>) => {
21
39
  for (const value of Object.values(props)) {
22
40
  if (isValue(value)) {
@@ -29,14 +47,18 @@ export const isAnimated = <T>(props: AnimatedProps<T>) => {
29
47
  export const materialize = <T>(props: AnimatedProps<T>) => {
30
48
  const result = { ...props };
31
49
  mapKeys(props).forEach((key) => {
32
- const value = props[key];
33
- if (isValue(value)) {
34
- result[key] = (value as SkiaValue<T[typeof key]>).current;
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];
35
55
  }
36
56
  });
37
57
  return result as T;
38
58
  };
39
59
 
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ export type AnimatedProp<T, P = any> = T | SkiaValue<T> | SkiaSelector<T, P>;
40
62
  export type AnimatedProps<T> = {
41
- [K in keyof T]: T[K] | SkiaValue<T[K]>;
63
+ [K in keyof T]: AnimatedProp<T[K]>;
42
64
  };
@@ -1,14 +1,14 @@
1
- import type { DependencyList } from "react";
2
- import { useRef, useEffect, useState } from "react";
3
- import { Image, Platform } from "react-native";
1
+ import { useEffect, useState } from "react";
2
+ import { Image } from "react-native";
4
3
 
5
4
  import { Skia } from "../Skia";
6
- import type { SkData, DataSource } from "../types";
5
+ import { isRNModule } from "../types";
6
+ import type { SkData, DataModule, DataSourceParam } from "../types";
7
7
 
8
- const resolveAsset = (source: ReturnType<typeof require>) => {
9
- return Platform.OS === "web"
10
- ? source.default
11
- : Image.resolveAssetSource(source).uri;
8
+ const resolveAsset = (source: DataModule) => {
9
+ return isRNModule(source)
10
+ ? Image.resolveAssetSource(source).uri
11
+ : source.default;
12
12
  };
13
13
 
14
14
  const factoryWrapper = <T>(
@@ -25,19 +25,12 @@ const factoryWrapper = <T>(
25
25
  }
26
26
  };
27
27
 
28
- const loadDataCollection = <T>(
29
- sources: DataSource[],
30
- factory: (data: SkData) => T,
31
- onError?: (err: Error) => void
32
- ): Promise<(T | null)[]> =>
33
- Promise.all(sources.map((source) => loadData(source, factory, onError)));
34
-
35
28
  const loadData = <T>(
36
- source: DataSource,
29
+ source: DataSourceParam,
37
30
  factory: (data: SkData) => T,
38
31
  onError?: (err: Error) => void
39
32
  ): Promise<T | null> => {
40
- if (source === null) {
33
+ if (source === null || source === undefined) {
41
34
  return new Promise((resolve) => resolve(null));
42
35
  } else if (source instanceof Uint8Array) {
43
36
  return new Promise((resolve) =>
@@ -50,51 +43,27 @@ const loadData = <T>(
50
43
  );
51
44
  }
52
45
  };
53
-
54
- type Source = DataSource | null | undefined;
55
-
56
46
  const useLoading = <T>(
57
- source: Source,
58
- loader: () => Promise<T | null>,
59
- deps: DependencyList = []
47
+ source: DataSourceParam,
48
+ loader: () => Promise<T | null>
60
49
  ) => {
61
50
  const [data, setData] = useState<T | null>(null);
62
- const prevSourceRef = useRef<Source>();
63
51
  useEffect(() => {
64
- if (prevSourceRef.current !== source) {
65
- prevSourceRef.current = source;
66
- loader().then(setData);
67
- } else {
68
- setData(null);
69
- }
52
+ loader().then(setData);
70
53
  // eslint-disable-next-line react-hooks/exhaustive-deps
71
- }, deps);
54
+ }, [source]);
72
55
  return data;
73
56
  };
74
57
 
75
- export const useDataCollection = <T>(
76
- sources: DataSource[],
77
- factory: (data: SkData) => T,
78
- onError?: (err: Error) => void,
79
- deps?: DependencyList
80
- ) =>
81
- useLoading(
82
- sources,
83
- () => loadDataCollection(sources, factory, onError),
84
- deps
85
- );
86
-
87
58
  export const useRawData = <T>(
88
- source: DataSource | null | undefined,
59
+ source: DataSourceParam,
89
60
  factory: (data: SkData) => T,
90
- onError?: (err: Error) => void,
91
- deps?: DependencyList
92
- ) => useLoading(source, () => loadData(source, factory, onError), deps);
61
+ onError?: (err: Error) => void
62
+ ) => useLoading(source, () => loadData(source, factory, onError));
93
63
 
94
64
  const identity = (data: SkData) => data;
95
65
 
96
66
  export const useData = (
97
- source: DataSource | null | undefined,
98
- onError?: (err: Error) => void,
99
- deps?: DependencyList
100
- ) => useRawData(source, identity, onError, deps);
67
+ source: DataSourceParam,
68
+ onError?: (err: Error) => void
69
+ ) => useRawData(source, identity, onError);
@@ -2,7 +2,7 @@
2
2
  import { useMemo } from "react";
3
3
 
4
4
  import { Skia } from "../Skia";
5
- import type { DataSource, SkFont } from "../types";
5
+ import type { DataSourceParam } from "../types";
6
6
 
7
7
  import { useTypeface } from "./Typeface";
8
8
 
@@ -10,10 +10,10 @@ import { useTypeface } from "./Typeface";
10
10
  * Returns a Skia Font object
11
11
  * */
12
12
  export const useFont = (
13
- font: DataSource | null | undefined,
13
+ font: DataSourceParam,
14
14
  size?: number,
15
15
  onError?: (err: Error) => void
16
- ): SkFont | null => {
16
+ ) => {
17
17
  const typeface = useTypeface(font, onError);
18
18
  return useMemo(() => {
19
19
  if (typeface && size) {
@@ -23,6 +23,5 @@ export const useFont = (
23
23
  } else {
24
24
  return null;
25
25
  }
26
- // eslint-disable-next-line react-hooks/exhaustive-deps
27
- }, [typeface]);
26
+ }, [size, typeface]);
28
27
  };
@@ -1,5 +1,5 @@
1
1
  import { Skia } from "../Skia";
2
- import type { DataSource } from "../types";
2
+ import type { DataSourceParam } from "../types";
3
3
 
4
4
  import { useRawData } from "./Data";
5
5
 
@@ -9,6 +9,6 @@ const imgFactory = Skia.Image.MakeImageFromEncoded.bind(Skia.Image);
9
9
  * Returns a Skia Image object
10
10
  * */
11
11
  export const useImage = (
12
- source: DataSource | null | undefined,
12
+ source: DataSourceParam,
13
13
  onError?: (err: Error) => void
14
14
  ) => useRawData(source, imgFactory, onError);
@@ -1,11 +1,11 @@
1
1
  import { Skia } from "../Skia";
2
- import type { DataSource } from "../types";
2
+ import type { DataSourceParam } from "../types";
3
3
 
4
4
  import { useRawData } from "./Data";
5
5
 
6
6
  const svgFactory = Skia.SVG.MakeFromData.bind(Skia.SVG);
7
7
 
8
8
  export const useSVG = (
9
- source: DataSource | null | undefined,
9
+ source: DataSourceParam,
10
10
  onError?: (err: Error) => void
11
11
  ) => useRawData(source, svgFactory, onError);
@@ -1,5 +1,5 @@
1
1
  import { Skia } from "../Skia";
2
- import type { DataSource } from "../types";
2
+ import type { DataSourceParam } from "../types";
3
3
 
4
4
  import { useRawData } from "./Data";
5
5
 
@@ -9,6 +9,6 @@ const tfFactory = Skia.Typeface.MakeFreeTypeFaceFromData.bind(Skia.Typeface);
9
9
  * Returns a Skia Typeface object
10
10
  * */
11
11
  export const useTypeface = (
12
- source: DataSource | null | undefined,
12
+ source: DataSourceParam,
13
13
  onError?: (err: Error) => void
14
14
  ) => useRawData(source, tfFactory, onError);
@@ -2,4 +2,14 @@ import type { SkJSIInstance } from "../JsiInstance";
2
2
 
3
3
  export type SkData = SkJSIInstance<"Data">;
4
4
 
5
- export type DataSource = ReturnType<typeof require> | string | Uint8Array;
5
+ type RNModule = number;
6
+ type ESModule = {
7
+ __esModule: true;
8
+ default: string;
9
+ };
10
+ export type DataModule = RNModule | ESModule;
11
+ export type DataSource = DataModule | string | Uint8Array;
12
+ export type DataSourceParam = DataSource | null | undefined;
13
+
14
+ export const isRNModule = (mod: DataModule): mod is RNModule =>
15
+ typeof mod === "number";
@@ -32,6 +32,7 @@ import {
32
32
  toOptionalValue,
33
33
  } from "./Host";
34
34
  import { JsiSkRect } from "./JsiSkRect";
35
+ import { JsiSkRRect } from "./JsiSkRRect";
35
36
 
36
37
  export class JsiSkCanvas
37
38
  extends HostObject<Canvas, "Canvas">
@@ -43,7 +44,7 @@ export class JsiSkCanvas
43
44
 
44
45
  drawRect(rect: SkRect, paint: SkPaint) {
45
46
  this.ref.drawRect(
46
- JsiSkRect.fromValue(this.CanvasKit, rect).ref,
47
+ JsiSkRect.fromValue(this.CanvasKit, rect),
47
48
  toValue<Paint>(paint)
48
49
  );
49
50
  }
@@ -61,8 +62,8 @@ export class JsiSkCanvas
61
62
  ) {
62
63
  this.ref.drawImageRect(
63
64
  toValue<Image>(img),
64
- JsiSkRect.fromValue(this.CanvasKit, src).ref,
65
- JsiSkRect.fromValue(this.CanvasKit, dest).ref,
65
+ JsiSkRect.fromValue(this.CanvasKit, src),
66
+ JsiSkRect.fromValue(this.CanvasKit, dest),
66
67
  toValue<Paint>(paint),
67
68
  fastSample
68
69
  );
@@ -130,8 +131,8 @@ export class JsiSkCanvas
130
131
  ) {
131
132
  this.ref.drawImageRectCubic(
132
133
  toValue<Image>(img),
133
- JsiSkRect.fromValue(this.CanvasKit, src).ref,
134
- JsiSkRect.fromValue(this.CanvasKit, dest).ref,
134
+ JsiSkRect.fromValue(this.CanvasKit, src),
135
+ JsiSkRect.fromValue(this.CanvasKit, dest),
135
136
  B,
136
137
  C,
137
138
  toOptionalValue(paint)
@@ -148,8 +149,8 @@ export class JsiSkCanvas
148
149
  ) {
149
150
  this.ref.drawImageRectOptions(
150
151
  toValue<Image>(img),
151
- JsiSkRect.fromValue(this.CanvasKit, src).ref,
152
- JsiSkRect.fromValue(this.CanvasKit, dest).ref,
152
+ JsiSkRect.fromValue(this.CanvasKit, src),
153
+ JsiSkRect.fromValue(this.CanvasKit, dest),
153
154
  ckEnum(fm),
154
155
  ckEnum(mm),
155
156
  toOptionalValue(paint)
@@ -217,7 +218,10 @@ export class JsiSkCanvas
217
218
  }
218
219
 
219
220
  drawRRect(rrect: SkRRect, paint: SkPaint) {
220
- this.ref.drawRRect(toValue(rrect), toValue(paint));
221
+ this.ref.drawRRect(
222
+ JsiSkRRect.fromValue(this.CanvasKit, rrect),
223
+ toValue(paint)
224
+ );
221
225
  }
222
226
 
223
227
  drawDRRect(outer: SkRRect, inner: SkRRect, paint: SkPaint) {
@@ -313,11 +317,19 @@ export class JsiSkCanvas
313
317
  }
314
318
 
315
319
  clipRect(rect: SkRect, op: ClipOp, doAntiAlias: boolean) {
316
- this.ref.clipRect(toValue(rect), ckEnum(op), doAntiAlias);
320
+ this.ref.clipRect(
321
+ JsiSkRect.fromValue(this.CanvasKit, rect),
322
+ ckEnum(op),
323
+ doAntiAlias
324
+ );
317
325
  }
318
326
 
319
327
  clipRRect(rrect: SkRRect, op: ClipOp, doAntiAlias: boolean) {
320
- this.ref.clipRRect(toValue(rrect), ckEnum(op), doAntiAlias);
328
+ this.ref.clipRRect(
329
+ JsiSkRRect.fromValue(this.CanvasKit, rrect),
330
+ ckEnum(op),
331
+ doAntiAlias
332
+ );
321
333
  }
322
334
 
323
335
  concat(m: SkMatrix) {
@@ -16,6 +16,7 @@ import type {
16
16
  import { ckEnum, HostObject, optEnum, toValue } from "./Host";
17
17
  import { JsiSkPoint } from "./JsiSkPoint";
18
18
  import { JsiSkRect } from "./JsiSkRect";
19
+ import { JsiSkRRect } from "./JsiSkRRect";
19
20
 
20
21
  const CommandCount = {
21
22
  [PathVerb.Move]: 3,
@@ -50,12 +51,20 @@ export class JsiSkPath extends HostObject<Path, "Path"> implements SkPath {
50
51
  startAngleInDegrees: number,
51
52
  sweepAngleInDegrees: number
52
53
  ) {
53
- this.ref.addArc(toValue(oval), startAngleInDegrees, sweepAngleInDegrees);
54
+ this.ref.addArc(
55
+ JsiSkRect.fromValue(this.CanvasKit, oval),
56
+ startAngleInDegrees,
57
+ sweepAngleInDegrees
58
+ );
54
59
  return this;
55
60
  }
56
61
 
57
62
  addOval(oval: SkRect, isCCW?: boolean, startIndex?: number) {
58
- this.ref.addOval(toValue(oval), isCCW, startIndex);
63
+ this.ref.addOval(
64
+ JsiSkRect.fromValue(this.CanvasKit, oval),
65
+ isCCW,
66
+ startIndex
67
+ );
59
68
  return this;
60
69
  }
61
70
 
@@ -183,7 +192,7 @@ export class JsiSkPath extends HostObject<Path, "Path"> implements SkPath {
183
192
  forceMoveTo: boolean
184
193
  ) {
185
194
  this.ref.arcToOval(
186
- toValue(oval),
195
+ JsiSkRect.fromValue(this.CanvasKit, oval),
187
196
  startAngleInDegrees,
188
197
  sweepAngleInDegrees,
189
198
  forceMoveTo
@@ -263,11 +272,11 @@ export class JsiSkPath extends HostObject<Path, "Path"> implements SkPath {
263
272
  }
264
273
 
265
274
  addRect(rect: SkRect, isCCW?: boolean) {
266
- this.ref.addRect(toValue(rect), isCCW);
275
+ this.ref.addRect(JsiSkRect.fromValue(this.CanvasKit, rect), isCCW);
267
276
  }
268
277
 
269
278
  addRRect(rrect: SkRRect, isCCW?: boolean) {
270
- this.ref.addRRect(toValue(rrect), isCCW);
279
+ this.ref.addRRect(JsiSkRRect.fromValue(this.CanvasKit, rrect), isCCW);
271
280
  return this;
272
281
  }
273
282
 
@@ -6,6 +6,17 @@ import { HostObject } from "./Host";
6
6
  import { JsiSkRect } from "./JsiSkRect";
7
7
 
8
8
  export class JsiSkRRect extends HostObject<RRect, "RRect"> implements SkRRect {
9
+ static fromValue(CanvasKit: CanvasKit, rect: SkRRect) {
10
+ if (rect instanceof JsiSkRect) {
11
+ return rect.ref;
12
+ }
13
+ return CanvasKit.RRectXY(
14
+ JsiSkRect.fromValue(CanvasKit, rect.rect),
15
+ rect.rx,
16
+ rect.ry
17
+ );
18
+ }
19
+
9
20
  constructor(CanvasKit: CanvasKit, ref: RRect) {
10
21
  super(CanvasKit, ref, "RRect");
11
22
  }
@@ -7,12 +7,9 @@ import { HostObject } from "./Host";
7
7
  export class JsiSkRect extends HostObject<Rect, "Rect"> implements SkRect {
8
8
  static fromValue(CanvasKit: CanvasKit, rect: SkRect) {
9
9
  if (rect instanceof JsiSkRect) {
10
- return rect;
10
+ return rect.ref;
11
11
  }
12
- return new JsiSkRect(
13
- CanvasKit,
14
- CanvasKit.XYWHRect(rect.x, rect.y, rect.width, rect.height)
15
- );
12
+ return CanvasKit.XYWHRect(rect.x, rect.y, rect.width, rect.height);
16
13
  }
17
14
 
18
15
  constructor(CanvasKit: CanvasKit, ref: Rect) {
@@ -1,4 +1,4 @@
1
- import { useMemo } from "react";
1
+ import { useEffect, useMemo } from "react";
2
2
 
3
3
  import { ValueApi } from "../api";
4
4
  import { isValue } from "../../renderer/processors/Animations";
@@ -10,9 +10,12 @@ import { isValue } from "../../renderer/processors/Animations";
10
10
  * @param values Dependant values
11
11
  * @returns A readonly value
12
12
  */
13
- export const useComputedValue = <R>(cb: () => R, values: unknown[]) =>
14
- useMemo(
13
+ export const useComputedValue = <R>(cb: () => R, values: unknown[]) => {
14
+ const value = useMemo(
15
15
  () => ValueApi.createComputedValue<R>(cb, values.filter(isValue)),
16
16
  // eslint-disable-next-line react-hooks/exhaustive-deps
17
17
  values
18
18
  );
19
+ useEffect(() => () => value.__invalidate(), [value]);
20
+ return value;
21
+ };
@@ -1,3 +1,4 @@
1
1
  export * from "./types";
2
2
  export * from "./hooks";
3
3
  export * from "./api";
4
+ export * from "./selector";
@@ -0,0 +1,24 @@
1
+ import type { SkiaValue } from "./types";
2
+
3
+ export type SkiaSelector<TReturn, TInput = unknown> = {
4
+ value: SkiaValue<TInput>;
5
+ selector: (v: TInput) => TReturn;
6
+ };
7
+
8
+ /**
9
+ * Wraps a Skia Value with a selector function. The selector function can access the
10
+ * inner values of the Skia Value so that we can dynamically ready array values and
11
+ * object values when doing animations in Skia.
12
+ * @param value Dependant value
13
+ * @param selector Selector function to calculate new value from the Skia Value's value
14
+ * @returns A descriptor that will be used by the reconciler to calculate the value
15
+ */
16
+ export const Selector = <TInput, TReturn>(
17
+ value: SkiaValue<TInput>,
18
+ selector: (v: TInput) => TReturn
19
+ ): SkiaSelector<TReturn, TInput> => {
20
+ return {
21
+ selector,
22
+ value,
23
+ };
24
+ };
@@ -8,6 +8,10 @@ export interface SkiaValue<T = number> {
8
8
  * Returns unsubscribe method.
9
9
  */
10
10
  addListener: (cb: (value: T) => void) => () => void;
11
+ /**
12
+ * Invalidates the value. Has different meaning depending on the type of the value.
13
+ */
14
+ __invalidate: () => void;
11
15
  /**
12
16
  * Field to make typechecking easier
13
17
  */
@@ -34,5 +34,11 @@ export class RNSkComputedValue<T> extends RNSkReadonlyValue<T> {
34
34
 
35
35
  public unsubscribe() {
36
36
  this._unsubscribers.forEach((unsubscribe) => unsubscribe());
37
+ this._unsubscribers = [];
38
+ }
39
+
40
+ public __invalidate(): void {
41
+ this._unsubscribers.forEach((unsubscribe) => unsubscribe());
42
+ this._unsubscribers = [];
37
43
  }
38
44
  }
@@ -29,4 +29,8 @@ export class RNSkReadonlyValue<T> implements SkiaValue<T> {
29
29
  this._listeners.splice(this._listeners.indexOf(cb), 1);
30
30
  };
31
31
  }
32
+
33
+ public __invalidate(): void {
34
+ this._listeners = [];
35
+ }
32
36
  }