@shopify/react-native-skia 0.1.133 → 0.1.137

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 (153) hide show
  1. package/README.md +4 -47
  2. package/android/CMakeLists.txt +1 -1
  3. package/android/build.gradle +17 -2
  4. package/cpp/api/JsiSkFont.h +25 -1
  5. package/cpp/api/JsiSkMatrix.h +12 -0
  6. package/cpp/rnskia/RNSkValueApi.h +6 -6
  7. package/cpp/rnskia/values/{RNSkDerivedValue.h → RNSkComputedValue.h} +7 -7
  8. package/ios/RNSkia-iOS/SkiaManager.mm +1 -1
  9. package/jestSetup.js +5 -0
  10. package/lib/commonjs/animation/functions/interpolate.js +3 -2
  11. package/lib/commonjs/animation/functions/interpolate.js.map +1 -1
  12. package/lib/commonjs/animation/functions/interpolateColors.js +2 -2
  13. package/lib/commonjs/animation/functions/interpolateColors.js.map +1 -1
  14. package/lib/commonjs/animation/functions/interpolatePaths.js +45 -11
  15. package/lib/commonjs/animation/functions/interpolatePaths.js.map +1 -1
  16. package/lib/commonjs/mock/index.js +134 -0
  17. package/lib/commonjs/mock/index.js.map +1 -0
  18. package/lib/commonjs/renderer/components/Group.js +1 -1
  19. package/lib/commonjs/renderer/components/Group.js.map +1 -1
  20. package/lib/commonjs/renderer/processors/Transform.js +8 -15
  21. package/lib/commonjs/renderer/processors/Transform.js.map +1 -1
  22. package/lib/commonjs/skia/core/Data.js +33 -43
  23. package/lib/commonjs/skia/core/Data.js.map +1 -1
  24. package/lib/commonjs/skia/core/Typeface.js +1 -1
  25. package/lib/commonjs/skia/core/Typeface.js.map +1 -1
  26. package/lib/commonjs/skia/types/Font/Font.js.map +1 -1
  27. package/lib/commonjs/skia/types/Matrix.js +17 -2
  28. package/lib/commonjs/skia/types/Matrix.js.map +1 -1
  29. package/lib/commonjs/skia/web/JsiSkFont.js +6 -0
  30. package/lib/commonjs/skia/web/JsiSkFont.js.map +1 -1
  31. package/lib/commonjs/skia/web/JsiSkMatrix.js +4 -0
  32. package/lib/commonjs/skia/web/JsiSkMatrix.js.map +1 -1
  33. package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
  34. package/lib/commonjs/values/api.js +1 -7
  35. package/lib/commonjs/values/api.js.map +1 -1
  36. package/lib/commonjs/values/api.web.js +3 -3
  37. package/lib/commonjs/values/api.web.js.map +1 -1
  38. package/lib/commonjs/values/hooks/index.js +4 -4
  39. package/lib/commonjs/values/hooks/index.js.map +1 -1
  40. package/lib/commonjs/values/hooks/useComputedValue.js +32 -0
  41. package/lib/commonjs/values/hooks/useComputedValue.js.map +1 -0
  42. package/lib/commonjs/values/web/{RNSkDerivedValue.js → RNSkComputedValue.js} +4 -4
  43. package/lib/commonjs/values/web/RNSkComputedValue.js.map +1 -0
  44. package/lib/commonjs/values/web/api.js +3 -3
  45. package/lib/commonjs/values/web/api.js.map +1 -1
  46. package/lib/commonjs/views/SkiaView.web.js +18 -18
  47. package/lib/commonjs/views/SkiaView.web.js.map +1 -1
  48. package/lib/commonjs/web/LoadSkiaWeb.js +25 -0
  49. package/lib/commonjs/web/LoadSkiaWeb.js.map +1 -0
  50. package/lib/commonjs/web/WithSkiaWeb.js +38 -0
  51. package/lib/commonjs/web/WithSkiaWeb.js.map +1 -0
  52. package/lib/commonjs/web/index.js +22 -12
  53. package/lib/commonjs/web/index.js.map +1 -1
  54. package/lib/module/animation/functions/interpolate.js +2 -2
  55. package/lib/module/animation/functions/interpolate.js.map +1 -1
  56. package/lib/module/animation/functions/interpolateColors.js +1 -1
  57. package/lib/module/animation/functions/interpolateColors.js.map +1 -1
  58. package/lib/module/animation/functions/interpolatePaths.js +44 -11
  59. package/lib/module/animation/functions/interpolatePaths.js.map +1 -1
  60. package/lib/module/mock/index.js +108 -0
  61. package/lib/module/mock/index.js.map +1 -0
  62. package/lib/module/renderer/components/Group.js +1 -1
  63. package/lib/module/renderer/components/Group.js.map +1 -1
  64. package/lib/module/renderer/processors/Transform.js +8 -15
  65. package/lib/module/renderer/processors/Transform.js.map +1 -1
  66. package/lib/module/skia/core/Data.js +32 -41
  67. package/lib/module/skia/core/Data.js.map +1 -1
  68. package/lib/module/skia/core/Typeface.js +1 -1
  69. package/lib/module/skia/core/Typeface.js.map +1 -1
  70. package/lib/module/skia/types/Font/Font.js.map +1 -1
  71. package/lib/module/skia/types/Matrix.js +11 -1
  72. package/lib/module/skia/types/Matrix.js.map +1 -1
  73. package/lib/module/skia/web/JsiSkFont.js +6 -0
  74. package/lib/module/skia/web/JsiSkFont.js.map +1 -1
  75. package/lib/module/skia/web/JsiSkMatrix.js +4 -0
  76. package/lib/module/skia/web/JsiSkMatrix.js.map +1 -1
  77. package/lib/module/skia/web/JsiSkia.js.map +1 -1
  78. package/lib/module/values/api.js +0 -4
  79. package/lib/module/values/api.js.map +1 -1
  80. package/lib/module/values/api.web.js +1 -1
  81. package/lib/module/values/api.web.js.map +1 -1
  82. package/lib/module/values/hooks/index.js +1 -1
  83. package/lib/module/values/hooks/index.js.map +1 -1
  84. package/lib/module/values/hooks/useComputedValue.js +18 -0
  85. package/lib/module/values/hooks/useComputedValue.js.map +1 -0
  86. package/lib/module/values/web/{RNSkDerivedValue.js → RNSkComputedValue.js} +2 -2
  87. package/lib/module/values/web/RNSkComputedValue.js.map +1 -0
  88. package/lib/module/values/web/api.js +3 -3
  89. package/lib/module/values/web/api.js.map +1 -1
  90. package/lib/module/views/SkiaView.web.js +18 -18
  91. package/lib/module/views/SkiaView.web.js.map +1 -1
  92. package/lib/module/web/LoadSkiaWeb.js +12 -0
  93. package/lib/module/web/LoadSkiaWeb.js.map +1 -0
  94. package/lib/module/web/WithSkiaWeb.js +22 -0
  95. package/lib/module/web/WithSkiaWeb.js.map +1 -0
  96. package/lib/module/web/index.js +2 -9
  97. package/lib/module/web/index.js.map +1 -1
  98. package/lib/typescript/jestSetup.d.ts +1 -0
  99. package/lib/typescript/src/animation/functions/interpolate.d.ts +6 -0
  100. package/lib/typescript/src/animation/functions/interpolatePaths.d.ts +3 -1
  101. package/lib/typescript/src/mock/index.d.ts +16 -0
  102. package/lib/typescript/src/renderer/Canvas.d.ts +1 -1
  103. package/lib/typescript/src/renderer/processors/Transform.d.ts +2 -2
  104. package/lib/typescript/src/skia/core/Data.d.ts +3 -3
  105. package/lib/typescript/src/skia/types/Font/Font.d.ts +6 -0
  106. package/lib/typescript/src/skia/types/Matrix.d.ts +5 -1
  107. package/lib/typescript/src/skia/types/Skia.d.ts +1 -1
  108. package/lib/typescript/src/skia/web/JsiSkFont.d.ts +1 -0
  109. package/lib/typescript/src/skia/web/JsiSkMatrix.d.ts +1 -0
  110. package/lib/typescript/src/values/api.d.ts +0 -1
  111. package/lib/typescript/src/values/api.web.d.ts +1 -1
  112. package/lib/typescript/src/values/hooks/index.d.ts +1 -1
  113. package/lib/typescript/src/values/hooks/{useDerivedValue.d.ts → useComputedValue.d.ts} +2 -1
  114. package/lib/typescript/src/values/types.d.ts +2 -2
  115. package/lib/typescript/src/values/web/{RNSkDerivedValue.d.ts → RNSkComputedValue.d.ts} +1 -1
  116. package/lib/typescript/src/views/SkiaView.web.d.ts +2 -2
  117. package/lib/typescript/src/web/LoadSkiaWeb.d.ts +6 -0
  118. package/lib/typescript/src/web/WithSkiaWeb.d.ts +10 -0
  119. package/lib/typescript/src/web/index.d.ts +2 -5
  120. package/package.json +8 -3
  121. package/scripts/setup-canvaskit.js +74 -0
  122. package/src/animation/functions/interpolate.ts +4 -2
  123. package/src/animation/functions/interpolateColors.ts +1 -1
  124. package/src/animation/functions/interpolatePaths.ts +59 -10
  125. package/src/mock/index.ts +110 -0
  126. package/src/renderer/components/Group.tsx +1 -1
  127. package/src/renderer/processors/Transform.ts +7 -10
  128. package/src/skia/core/Data.ts +67 -50
  129. package/src/skia/core/Typeface.ts +6 -1
  130. package/src/skia/types/Font/Font.ts +7 -0
  131. package/src/skia/types/Matrix.ts +18 -2
  132. package/src/skia/types/Skia.ts +1 -1
  133. package/src/skia/web/JsiSkFont.ts +6 -0
  134. package/src/skia/web/JsiSkMatrix.ts +4 -0
  135. package/src/skia/web/JsiSkia.ts +1 -1
  136. package/src/values/api.ts +0 -2
  137. package/src/values/api.web.ts +1 -1
  138. package/src/values/hooks/index.ts +1 -1
  139. package/src/values/hooks/useComputedValue.ts +23 -0
  140. package/src/values/types.ts +2 -2
  141. package/src/values/web/{RNSkDerivedValue.ts → RNSkComputedValue.ts} +1 -1
  142. package/src/values/web/api.ts +3 -3
  143. package/src/views/SkiaView.web.tsx +27 -24
  144. package/src/web/LoadSkiaWeb.tsx +18 -0
  145. package/src/web/WithSkiaWeb.tsx +32 -0
  146. package/src/web/index.ts +2 -15
  147. package/lib/commonjs/values/hooks/useDerivedValue.js +0 -25
  148. package/lib/commonjs/values/hooks/useDerivedValue.js.map +0 -1
  149. package/lib/commonjs/values/web/RNSkDerivedValue.js.map +0 -1
  150. package/lib/module/values/hooks/useDerivedValue.js +0 -14
  151. package/lib/module/values/hooks/useDerivedValue.js.map +0 -1
  152. package/lib/module/values/web/RNSkDerivedValue.js.map +0 -1
  153. package/src/values/hooks/useDerivedValue.ts +0 -18
@@ -29,8 +29,8 @@ export declare class SkiaView extends React.Component<SkiaViewProps, {
29
29
  /**
30
30
  * Sends a redraw request to the native SkiaView.
31
31
  */
32
- private redraw;
33
- requestRedraw(): void;
32
+ private tick;
33
+ redraw(): void;
34
34
  /**
35
35
  * Updates the drawing mode for the skia view. This is the same
36
36
  * as declaratively setting the mode property on the SkiaView.
@@ -0,0 +1,6 @@
1
+ import type { CanvasKit as CanvasKitType } from "canvaskit-wasm";
2
+ declare global {
3
+ var CanvasKit: CanvasKitType;
4
+ }
5
+ export declare const LoadSkiaWeb: () => Promise<void>;
6
+ export declare const LoadSkia: () => Promise<void>;
@@ -0,0 +1,10 @@
1
+ import type { ComponentProps, ComponentType } from "react";
2
+ import { Suspense } from "react";
3
+ interface WithSkiaProps {
4
+ fallback: ComponentProps<typeof Suspense>["fallback"];
5
+ getComponent: () => Promise<{
6
+ default: ComponentType;
7
+ }>;
8
+ }
9
+ export declare const WithSkiaWeb: ({ getComponent, fallback }: WithSkiaProps) => JSX.Element;
10
+ export {};
@@ -1,5 +1,2 @@
1
- import type { CanvasKit as CanvasKitType } from "canvaskit-wasm";
2
- declare global {
3
- var CanvasKit: CanvasKitType;
4
- }
5
- export declare const LoadSkia: () => Promise<void>;
1
+ export * from "./LoadSkiaWeb";
2
+ export * from "./WithSkiaWeb";
package/package.json CHANGED
@@ -3,8 +3,11 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
+ "bin": {
7
+ "setup-skia-web": "./scripts/setup-canvaskit.js"
8
+ },
6
9
  "title": "React Native Skia",
7
- "version": "0.1.133",
10
+ "version": "0.1.137",
8
11
  "description": "High-performance React Native Graphics using Skia",
9
12
  "main": "lib/module/index.js",
10
13
  "files": [
@@ -21,6 +24,7 @@
21
24
  "android/src/**",
22
25
  "libs/android/**",
23
26
  "index.js",
27
+ "jestSetup.js",
24
28
  "cpp/**/*.{h,cpp}",
25
29
  "ios",
26
30
  "libs/ios/libskia.xcframework",
@@ -28,6 +32,7 @@
28
32
  "libs/ios/libsvg.xcframework",
29
33
  "react-native-skia.podspec",
30
34
  "scripts/install-npm.js",
35
+ "scripts/setup-canvaskit.js",
31
36
  "dist/**"
32
37
  ],
33
38
  "scripts": {
@@ -70,8 +75,8 @@
70
75
  "@types/react-reconciler": "^0.26.4",
71
76
  "eslint": "7.32.0",
72
77
  "eslint-config-react-native-wcandillon": "^3.7.2",
78
+ "eslint-plugin-reanimated": "^1.2.6",
73
79
  "jest": "^27.4.3",
74
- "patch-package": "^6.4.7",
75
80
  "react": "17.0.2",
76
81
  "react-native": "0.66.2",
77
82
  "react-native-builder-bob": "^0.18.2",
@@ -79,7 +84,7 @@
79
84
  "typescript": "^4.6.4"
80
85
  },
81
86
  "dependencies": {
82
- "canvaskit-wasm": "^0.34.0",
87
+ "canvaskit-wasm": "^0.35.0",
83
88
  "react-reconciler": "^0.26.2"
84
89
  },
85
90
  "eslintIgnore": [
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable max-len */
3
+
4
+ /**
5
+ * A script to automate the setup of `@shopify/react-native-skia` for web.
6
+ * The only requirement is that your project supports a 'static' folder (often named '/public').
7
+ * In `@expo/webpack-config` this is `./web` (default for now).
8
+ *
9
+ * This script does the following:
10
+ * 1. Resolve the public path relative to wherever the script is being run.
11
+ * 2. Log out some useful info about the web setup, just in case anything goes wrong.
12
+ * 3. Resolve the installed wasm file `canvaskit-wasm/bin/full/canvaskit.wasm`
13
+ * from `@shopify/react-native-skia -> canvaskit`.
14
+ * 4. Recursively ensure the path exists and copy the file into the desired location.
15
+ *
16
+ *
17
+ * Usage:
18
+ * $ `npx <script> web`
19
+ *
20
+ * -> Copies the file to `<project>/web/static/js/canvaskit.wasm`
21
+ *
22
+ * Tooling that uses `/public`:
23
+ * $ `npx <script> public`
24
+ *
25
+ * -> Copies the file to `<project>/public/static/js/canvaskit.wasm`
26
+ */
27
+ const fs = require("fs");
28
+ const path = require("path");
29
+
30
+ const args = process.argv.slice(2);
31
+
32
+ const gray = (text) => `\x1b[90m${text}\x1b[0m`;
33
+ const lime = (text) => `\x1b[32m${text}\x1b[0m`;
34
+
35
+ function getWasmFilePath() {
36
+ try {
37
+ return require.resolve("canvaskit-wasm/bin/full/canvaskit.wasm");
38
+ } catch (error) {
39
+ console.error(
40
+ `Could not find 'canvaskit-wasm'. Please install '@shopify/react-native-skia' and ensure it can be resolved from your project: ${process.cwd()}`
41
+ );
42
+ process.exit(1);
43
+ }
44
+ }
45
+
46
+ function getOutputFilePath() {
47
+ // Default to using `web` public path.
48
+ const publicFolder = path.resolve(args[0] || "web");
49
+ const publicLocation = "./static/js/canvaskit.wasm";
50
+ const output = path.join(publicFolder, publicLocation);
51
+
52
+ console.log(
53
+ `› Copying 'canvaskit.wasm' file to static folder:\n ${gray(output)}\n`
54
+ );
55
+ return output;
56
+ }
57
+
58
+ function copyFile(from, to) {
59
+ const data = fs.readFileSync(from);
60
+ fs.mkdirSync(path.dirname(to), { recursive: true });
61
+ fs.writeFileSync(to, data);
62
+ }
63
+
64
+ // Copy the WASM file to `<static>/static/js/canvaskit.wasm`
65
+ (() => {
66
+ copyFile(getWasmFilePath(), getOutputFilePath());
67
+
68
+ console.log(lime("› Success! You are almost there:"));
69
+ console.log(
70
+ gray(
71
+ "› To load React Native Skia Web, follow these instructions : https://shopify.github.io/react-native-skia/docs/getting-started/web"
72
+ )
73
+ );
74
+ })();
@@ -60,7 +60,9 @@ function isExtrapolate(value: string): value is Extrapolate {
60
60
 
61
61
  // validates extrapolations type
62
62
  // if type is correct, converts it to ExtrapolationConfig
63
- function validateType(type: ExtrapolationType): RequiredExtrapolationConfig {
63
+ export function validateInterpolationOptions(
64
+ type: ExtrapolationType
65
+ ): RequiredExtrapolationConfig {
64
66
  // initialize extrapolationConfig with default extrapolation
65
67
  const extrapolationConfig: RequiredExtrapolationConfig = {
66
68
  extrapolateLeft: Extrapolate.EXTEND,
@@ -151,7 +153,7 @@ export function interpolate(
151
153
  );
152
154
  }
153
155
 
154
- const extrapolationConfig = validateType(type);
156
+ const extrapolationConfig = validateInterpolationOptions(type);
155
157
  const { length } = input;
156
158
  const narrowedInput: InterpolationNarrowedInput = {
157
159
  leftEdgeInput: input[0],
@@ -1,4 +1,4 @@
1
- import { mix } from "../../renderer";
1
+ import { mix } from "../../renderer/processors/math";
2
2
  import type { Color, SkColor } from "../../skia";
3
3
  import { Skia } from "../../skia";
4
4
 
@@ -1,10 +1,26 @@
1
1
  import type { SkPath } from "../../skia/types";
2
+ import { exhaustiveCheck } from "../../renderer/typeddash";
3
+
4
+ import type { ExtrapolationType } from "./interpolate";
5
+ import { validateInterpolationOptions, Extrapolate } from "./interpolate";
6
+
7
+ const lerp = (
8
+ value: number,
9
+ from: number,
10
+ to: number,
11
+ p1: SkPath,
12
+ p2: SkPath
13
+ ) => {
14
+ const t = (value - from) / (to - from);
15
+ return p2.interpolate(p1, t)!;
16
+ };
2
17
 
3
18
  /**
4
19
  * Maps an input value within a range to an output path within a path range.
5
20
  * @param value - The input value.
6
21
  * @param inputRange - The range of the input value.
7
22
  * @param outputRange - The range of the output path.
23
+ * @param options - Extrapolation options
8
24
  * @returns The output path.
9
25
  * @example <caption>Map a value between 0 and 1 to a path between two paths.</caption>
10
26
  * const path1 = new Path();
@@ -18,21 +34,54 @@ import type { SkPath } from "../../skia/types";
18
34
  export const interpolatePaths = (
19
35
  value: number,
20
36
  input: number[],
21
- outputRange: SkPath[]
37
+ outputRange: SkPath[],
38
+ options?: ExtrapolationType
22
39
  ) => {
40
+ const extrapolation = validateInterpolationOptions(options);
41
+ if (value < input[0]) {
42
+ switch (extrapolation.extrapolateLeft) {
43
+ case Extrapolate.CLAMP:
44
+ return outputRange[0];
45
+ case Extrapolate.EXTEND:
46
+ return lerp(value, input[0], input[1], outputRange[0], outputRange[1]);
47
+ case Extrapolate.IDENTITY:
48
+ throw new Error(
49
+ "Identity is not a supported extrapolation type for interpolatePaths()"
50
+ );
51
+ default:
52
+ exhaustiveCheck(extrapolation.extrapolateLeft);
53
+ }
54
+ } else if (value > input[input.length - 1]) {
55
+ switch (extrapolation.extrapolateRight) {
56
+ case Extrapolate.CLAMP:
57
+ return outputRange[outputRange.length - 1];
58
+ case Extrapolate.EXTEND:
59
+ return lerp(
60
+ value,
61
+ input[input.length - 2],
62
+ input[input.length - 1],
63
+ outputRange[input.length - 2],
64
+ outputRange[input.length - 1]
65
+ );
66
+ case Extrapolate.IDENTITY:
67
+ throw new Error(
68
+ "Identity is not a supported extrapolation type for interpolatePaths()"
69
+ );
70
+ default:
71
+ exhaustiveCheck(extrapolation.extrapolateRight);
72
+ }
73
+ }
23
74
  let i = 0;
24
75
  for (; i <= input.length - 1; i++) {
25
76
  if (value >= input[i] && value <= input[i + 1]) {
26
77
  break;
27
78
  }
28
- if (i === input.length - 1) {
29
- if (value < input[0]) {
30
- return outputRange[0];
31
- } else {
32
- return outputRange[i];
33
- }
34
- }
35
79
  }
36
- const t = (value - input[i]) / (input[i + 1] - input[i]);
37
- return outputRange[i + 1].interpolate(outputRange[i], t)!;
80
+ return lerp(
81
+ value,
82
+ input[i],
83
+ input[i + 1],
84
+ outputRange[i],
85
+ outputRange[i + 1]
86
+ );
38
87
  };
@@ -0,0 +1,110 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import type { Color, Skia as SkiaApi, SkRect, Vector } from "../skia/types";
4
+ import * as Values from "../values/web";
5
+ import * as ValuesHooks from "../values/hooks";
6
+ import * as BaseSkia from "../skia/types";
7
+ import type * as SkiaExports from "../skia";
8
+ import type * as ExternalExports from "../external";
9
+ import type * as ValueExports from "../values";
10
+ import type * as AnimationExports from "../animation";
11
+ import { useSharedValueEffect } from "../external/reanimated/useSharedValueEffect";
12
+ import * as timingFunctions from "../animation/timing";
13
+ import * as springFunctions from "../animation/spring";
14
+ import * as decayFunctions from "../animation/decay";
15
+ import * as interpolateFn from "../animation/functions/interpolate";
16
+ import * as interpolatePathFn from "../animation/functions/interpolatePaths";
17
+ import * as interpolateVectorFn from "../animation/functions/interpolateVector";
18
+ import { ShaderLib } from "../renderer/components/shaders/ShaderLib";
19
+
20
+ class Stub {
21
+ constructor() {
22
+ return new Proxy(() => {}, {
23
+ get: () => new Stub(),
24
+ apply: () => new Stub(),
25
+ set: () => true,
26
+ });
27
+ }
28
+ }
29
+
30
+ const Noop: () => any = () => {};
31
+
32
+ export const Skia: SkiaApi = new Stub() as any;
33
+
34
+ export const vec = (x?: number, y?: number) => ({ x: x ?? 0, y: y ?? x ?? 0 });
35
+
36
+ export const Mock: typeof SkiaExports &
37
+ typeof ExternalExports &
38
+ typeof ValueExports &
39
+ typeof AnimationExports & {
40
+ createDrawing: () => any;
41
+ createDeclaration: () => any;
42
+ ShaderLib: typeof ShaderLib;
43
+ } = {
44
+ // SkiaExports
45
+ // 1. Skia API. BaseSkia contains the enums, and functions like isPaint etc
46
+ Skia,
47
+ ...BaseSkia,
48
+ // 2. Hooks
49
+ useDataCollection: Noop,
50
+ useRawData: Noop,
51
+ useData: Noop,
52
+ useFont: Noop,
53
+ useTypeface: Noop,
54
+ useImage: Noop,
55
+ usePath: Noop,
56
+ useSVG: Noop,
57
+ useTextPath: Noop,
58
+ usePaint: Noop,
59
+ usePicture: Noop,
60
+ useSvgPath: Noop,
61
+ // 3. Point/Rect/Transform utilities
62
+ vec,
63
+ rect: (x: number, y: number, width: number, height: number) => ({
64
+ x,
65
+ y,
66
+ width,
67
+ height,
68
+ }),
69
+ rrect: (r: SkRect, rx: number, ry: number) => ({
70
+ rect: r,
71
+ rx,
72
+ ry,
73
+ }),
74
+ point: vec,
75
+ add: (a: Vector, b: Vector) => vec(a.x + b.x, a.y + b.y),
76
+ sub: (a: Vector, b: Vector) => vec(a.x - b.x, a.y - b.y),
77
+ neg: (a: Vector) => vec(-a.x, -a.y),
78
+ dist: (a: Vector, b: Vector) => Math.hypot(a.x - b.x, a.y - b.y),
79
+ translate: ({ x, y }: Vector) =>
80
+ [{ translateX: x }, { translateY: y }] as const,
81
+
82
+ bounds: Noop,
83
+ topLeft: Noop,
84
+ topRight: Noop,
85
+ bottomLeft: Noop,
86
+ bottomRight: Noop,
87
+ center: Noop,
88
+ processTransform2d: Noop,
89
+ // ExternalExports
90
+ useSharedValueEffect,
91
+ // ValueExports
92
+ ...Values,
93
+ ...ValuesHooks,
94
+ // Animations
95
+ ...timingFunctions,
96
+ ...springFunctions,
97
+ ...decayFunctions,
98
+ ...interpolateFn,
99
+ ...interpolatePathFn,
100
+ ...interpolateVectorFn,
101
+ interpolateColors: (
102
+ _value: number,
103
+ _inputRange: number[],
104
+ _outputRange: Color[]
105
+ ) => Float32Array.of(0, 0, 0, 0),
106
+ mixColors: (_v: number, _x: Color, _y: Color) => Float32Array.of(0, 0, 0, 0),
107
+ ShaderLib,
108
+ createDrawing: Noop,
109
+ createDeclaration: Noop,
110
+ };
@@ -58,7 +58,7 @@ const onDraw = createDrawing<GroupProps>(
58
58
  } else {
59
59
  canvas.save();
60
60
  }
61
- processCanvasTransform(ctx, groupProps);
61
+ processCanvasTransform(canvas, groupProps);
62
62
  if (clip) {
63
63
  const op = invertClip ? ClipOp.Difference : ClipOp.Intersect;
64
64
  processClip(Skia, canvas, clip, op);
@@ -1,6 +1,6 @@
1
- import type { DrawingContext } from "../DrawingContext";
2
1
  import type { SkMatrix, Vector, Transforms2d } from "../../skia/types";
3
2
  import { processTransform } from "../../skia/types";
3
+ import type { SkCanvas } from "../../skia/types/Canvas";
4
4
 
5
5
  export interface TransformProps {
6
6
  transform?: Transforms2d;
@@ -9,25 +9,22 @@ export interface TransformProps {
9
9
  }
10
10
 
11
11
  export const processCanvasTransform = (
12
- { canvas, Skia }: DrawingContext,
12
+ canvas: SkCanvas,
13
13
  { transform, origin, matrix }: TransformProps
14
14
  ) => {
15
15
  if (matrix) {
16
16
  if (origin) {
17
- const m3 = Skia.Matrix();
18
- m3.translate(origin.x, origin.y);
19
- m3.concat(matrix);
20
- m3.translate(-origin.x, -origin.y);
21
- canvas.concat(m3);
17
+ canvas.translate(origin.x, origin.y);
18
+ canvas.concat(matrix);
19
+ canvas.translate(-origin.x, -origin.y);
22
20
  } else {
23
21
  canvas.concat(matrix);
24
22
  }
25
23
  } else if (transform) {
26
- const m3 = processTransform(
27
- Skia.Matrix(),
24
+ processTransform(
25
+ canvas,
28
26
  origin ? transformOrigin(origin, transform) : transform
29
27
  );
30
- canvas.concat(m3);
31
28
  }
32
29
  };
33
30
 
@@ -11,71 +11,88 @@ const resolveAsset = (source: ReturnType<typeof require>) => {
11
11
  : Image.resolveAssetSource(source).uri;
12
12
  };
13
13
 
14
- export const useDataCollection = <T>(
15
- sources: DataSource[],
16
- factory: (data: SkData[]) => T,
17
- deps: DependencyList = []
14
+ const factoryWrapper = <T>(
15
+ data2: SkData,
16
+ factory: (data: SkData) => T,
17
+ onError?: (err: Error) => void
18
18
  ) => {
19
- const [data, setData] = useState<T | null>(null);
20
- useEffect(() => {
21
- const bytesOrURIs = sources.map((source) => {
22
- if (source instanceof Uint8Array) {
23
- return source;
24
- }
25
- return typeof source === "string" ? source : resolveAsset(source);
26
- });
27
- Promise.all(
28
- bytesOrURIs.map((bytesOrURI) =>
29
- bytesOrURI instanceof Uint8Array
30
- ? Skia.Data.fromBytes(bytesOrURI)
31
- : Skia.Data.fromURI(bytesOrURI)
32
- )
33
- ).then((d) => setData(factory(d)));
34
- // eslint-disable-next-line react-hooks/exhaustive-deps
35
- }, deps);
36
- return data;
19
+ const factoryResult = factory(data2);
20
+ if (factoryResult === null) {
21
+ onError && onError(new Error("Could not load data"));
22
+ return null;
23
+ } else {
24
+ return factoryResult;
25
+ }
37
26
  };
38
27
 
39
- export const useRawData = <T>(
40
- source: DataSource | null | undefined,
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
+ const loadData = <T>(
36
+ source: DataSource,
41
37
  factory: (data: SkData) => T,
42
38
  onError?: (err: Error) => void
39
+ ): Promise<T | null> => {
40
+ if (source instanceof Uint8Array) {
41
+ return new Promise((resolve) =>
42
+ resolve(factoryWrapper(Skia.Data.fromBytes(source), factory, onError))
43
+ );
44
+ } else {
45
+ const uri = typeof source === "string" ? source : resolveAsset(source);
46
+ return Skia.Data.fromURI(uri).then((d) =>
47
+ factoryWrapper(d, factory, onError)
48
+ );
49
+ }
50
+ };
51
+
52
+ type Source = DataSource | null | undefined;
53
+
54
+ const useLoading = <T>(
55
+ source: Source,
56
+ loader: () => Promise<T | null>,
57
+ deps: DependencyList = []
43
58
  ) => {
44
59
  const [data, setData] = useState<T | null>(null);
45
- const prevSourceRef = useRef<DataSource | null | undefined>();
60
+ const prevSourceRef = useRef<Source>();
46
61
  useEffect(() => {
47
- // Track to avoid re-fetching the same data
48
62
  if (prevSourceRef.current !== source) {
49
63
  prevSourceRef.current = source;
50
- if (source !== null && source !== undefined) {
51
- const factoryWrapper = (data2: SkData) => {
52
- const factoryResult = factory(data2);
53
- if (factoryResult === null) {
54
- onError && onError(new Error("Could not load data"));
55
- setData(null);
56
- } else {
57
- setData(factoryResult);
58
- }
59
- };
60
- if (source instanceof Uint8Array) {
61
- factoryWrapper(Skia.Data.fromBytes(source));
62
- } else {
63
- const uri =
64
- typeof source === "string" ? source : resolveAsset(source);
65
- Skia.Data.fromURI(uri).then((d) => factoryWrapper(d));
66
- }
67
- } else {
68
- // new source is null or undefined -> remove cached data
69
- setData(null);
70
- }
64
+ loader().then(setData);
65
+ } else {
66
+ setData(null);
71
67
  }
72
- }, [factory, onError, source]);
68
+ // eslint-disable-next-line react-hooks/exhaustive-deps
69
+ }, deps);
73
70
  return data;
74
71
  };
75
72
 
73
+ export const useDataCollection = <T>(
74
+ sources: DataSource[],
75
+ factory: (data: SkData) => T,
76
+ onError?: (err: Error) => void,
77
+ deps?: DependencyList
78
+ ) =>
79
+ useLoading(
80
+ sources,
81
+ () => loadDataCollection(sources, factory, onError),
82
+ deps
83
+ );
84
+
85
+ export const useRawData = <T>(
86
+ source: DataSource | null | undefined,
87
+ factory: (data: SkData) => T,
88
+ onError?: (err: Error) => void,
89
+ deps?: DependencyList
90
+ ) => useLoading(source, () => loadData(source, factory, onError), deps);
91
+
76
92
  const identity = (data: SkData) => data;
77
93
 
78
94
  export const useData = (
79
95
  source: DataSource | null | undefined,
80
- onError?: (err: Error) => void
81
- ) => useRawData(source, identity, onError);
96
+ onError?: (err: Error) => void,
97
+ deps?: DependencyList
98
+ ) => useRawData(source, identity, onError, deps);
@@ -8,4 +8,9 @@ import { useRawData } from "./Data";
8
8
  export const useTypeface = (
9
9
  source: DataSource | null | undefined,
10
10
  onError?: (err: Error) => void
11
- ) => useRawData(source, Skia.Typeface.MakeFreeTypeFaceFromData, onError);
11
+ ) =>
12
+ useRawData(
13
+ source,
14
+ Skia.Typeface.MakeFreeTypeFaceFromData.bind(Skia.Typeface),
15
+ onError
16
+ );
@@ -12,6 +12,13 @@ export interface FontMetrics {
12
12
  }
13
13
 
14
14
  export interface SkFont extends SkJSIInstance<"Font"> {
15
+ /**
16
+ * Retrieves the total width of the provided text
17
+ * @param text
18
+ * @param paint
19
+ */
20
+ getTextWidth(text: string, paint?: SkPaint): number;
21
+
15
22
  /**
16
23
  * Retrieves the advanceX measurements for each glyph.
17
24
  * If paint is not null, its stroking, PathEffect, and MaskFilter fields are respected.
@@ -1,4 +1,5 @@
1
1
  import type { SkJSIInstance } from "./JsiInstance";
2
+ import type { SkCanvas } from "./Canvas";
2
3
  export enum MatrixIndex {
3
4
  ScaleX = 0,
4
5
  SkewX = 1,
@@ -11,12 +12,16 @@ export enum MatrixIndex {
11
12
  persp2 = 8,
12
13
  }
13
14
 
15
+ export const isMatrix = (obj: unknown): obj is SkMatrix =>
16
+ obj !== null && (obj as SkJSIInstance<string>).__typename__ === "Matrix";
17
+
14
18
  export interface SkMatrix extends SkJSIInstance<"Matrix"> {
15
19
  concat: (matrix: SkMatrix) => void;
16
20
  translate: (x: number, y: number) => void;
17
21
  scale: (x: number, y?: number) => void;
18
22
  skew: (x: number, y: number) => void;
19
23
  rotate: (theta: number) => void;
24
+ identity: () => void;
20
25
  }
21
26
 
22
27
  type Transform2dName =
@@ -49,7 +54,10 @@ export interface TransformProp {
49
54
  transform?: Transforms2d;
50
55
  }
51
56
 
52
- export const processTransform = (m: SkMatrix, transforms: Transforms2d) => {
57
+ export const processTransform = <T extends SkMatrix | SkCanvas>(
58
+ m: T,
59
+ transforms: Transforms2d
60
+ ) => {
53
61
  for (const transform of transforms) {
54
62
  const key = Object.keys(transform)[0] as Transform2dName;
55
63
  const value = (transform as Pick<Transformations, typeof key>)[key];
@@ -82,7 +90,11 @@ export const processTransform = (m: SkMatrix, transforms: Transforms2d) => {
82
90
  continue;
83
91
  }
84
92
  if (key === "rotate" || key === "rotateZ") {
85
- m.rotate(value);
93
+ if (isMatrix(m)) {
94
+ m.rotate(value);
95
+ } else {
96
+ m.rotate(toDegrees(value), 0, 0);
97
+ }
86
98
  continue;
87
99
  }
88
100
  exhaustiveCheck(key);
@@ -93,3 +105,7 @@ export const processTransform = (m: SkMatrix, transforms: Transforms2d) => {
93
105
  const exhaustiveCheck = (a: never): never => {
94
106
  throw new Error(`Unknown transformation: ${a}`);
95
107
  };
108
+
109
+ export const toDegrees = (rad: number) => {
110
+ return (rad * 180) / Math.PI;
111
+ };
@@ -48,7 +48,7 @@ export interface Skia {
48
48
  PictureRecorder: () => SkPictureRecorder;
49
49
  Picture: PictureFactory;
50
50
  Path: PathFactory;
51
- Matrix: (matrix?: number[]) => SkMatrix;
51
+ Matrix: (matrix?: readonly number[]) => SkMatrix;
52
52
  ColorFilter: ColorFilterFactory;
53
53
  Font: (typeface?: SkTypeface, size?: number) => SkFont;
54
54
  Typeface: TypefaceFactory;