@shopify/react-native-skia 0.1.141 → 0.1.142

Sign up to get free protection for your applications and to get access to all the features.
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
  }