@shopify/react-native-skia 0.1.134 → 0.1.138

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 (108) hide show
  1. package/README.md +4 -47
  2. package/android/build.gradle +1 -2
  3. package/cpp/api/JsiSkFont.h +25 -1
  4. package/cpp/api/JsiSkMatrix.h +12 -0
  5. package/cpp/api/JsiSkTypeface.h +1 -29
  6. package/jestSetup.js +5 -0
  7. package/lib/commonjs/animation/functions/interpolate.js +3 -2
  8. package/lib/commonjs/animation/functions/interpolate.js.map +1 -1
  9. package/lib/commonjs/animation/functions/interpolateColors.js +2 -2
  10. package/lib/commonjs/animation/functions/interpolateColors.js.map +1 -1
  11. package/lib/commonjs/animation/functions/interpolatePaths.js +45 -11
  12. package/lib/commonjs/animation/functions/interpolatePaths.js.map +1 -1
  13. package/lib/commonjs/mock/index.js +121 -177
  14. package/lib/commonjs/mock/index.js.map +1 -1
  15. package/lib/commonjs/renderer/components/Group.js +1 -1
  16. package/lib/commonjs/renderer/components/Group.js.map +1 -1
  17. package/lib/commonjs/renderer/processors/Transform.js +8 -15
  18. package/lib/commonjs/renderer/processors/Transform.js.map +1 -1
  19. package/lib/commonjs/skia/core/Data.js +7 -4
  20. package/lib/commonjs/skia/core/Data.js.map +1 -1
  21. package/lib/commonjs/skia/types/Font/Font.js.map +1 -1
  22. package/lib/commonjs/skia/types/Matrix.js +18 -3
  23. package/lib/commonjs/skia/types/Matrix.js.map +1 -1
  24. package/lib/commonjs/skia/web/JsiSkFont.js +6 -0
  25. package/lib/commonjs/skia/web/JsiSkFont.js.map +1 -1
  26. package/lib/commonjs/skia/web/JsiSkMatrix.js +4 -0
  27. package/lib/commonjs/skia/web/JsiSkMatrix.js.map +1 -1
  28. package/lib/commonjs/values/api.js +1 -7
  29. package/lib/commonjs/values/api.js.map +1 -1
  30. package/lib/commonjs/values/hooks/useComputedValue.js +2 -2
  31. package/lib/commonjs/values/hooks/useComputedValue.js.map +1 -1
  32. package/lib/commonjs/views/SkiaView.web.js +27 -37
  33. package/lib/commonjs/views/SkiaView.web.js.map +1 -1
  34. package/lib/commonjs/web/LoadSkiaWeb.js +29 -0
  35. package/lib/commonjs/web/LoadSkiaWeb.js.map +1 -0
  36. package/lib/commonjs/web/WithSkiaWeb.js +39 -0
  37. package/lib/commonjs/web/WithSkiaWeb.js.map +1 -0
  38. package/lib/commonjs/web/index.js +22 -12
  39. package/lib/commonjs/web/index.js.map +1 -1
  40. package/lib/module/animation/functions/interpolate.js +2 -2
  41. package/lib/module/animation/functions/interpolate.js.map +1 -1
  42. package/lib/module/animation/functions/interpolateColors.js +1 -1
  43. package/lib/module/animation/functions/interpolateColors.js.map +1 -1
  44. package/lib/module/animation/functions/interpolatePaths.js +44 -11
  45. package/lib/module/animation/functions/interpolatePaths.js.map +1 -1
  46. package/lib/module/mock/index.js +103 -147
  47. package/lib/module/mock/index.js.map +1 -1
  48. package/lib/module/renderer/components/Group.js +1 -1
  49. package/lib/module/renderer/components/Group.js.map +1 -1
  50. package/lib/module/renderer/processors/Transform.js +8 -15
  51. package/lib/module/renderer/processors/Transform.js.map +1 -1
  52. package/lib/module/skia/core/Data.js +7 -4
  53. package/lib/module/skia/core/Data.js.map +1 -1
  54. package/lib/module/skia/types/Font/Font.js.map +1 -1
  55. package/lib/module/skia/types/Matrix.js +12 -2
  56. package/lib/module/skia/types/Matrix.js.map +1 -1
  57. package/lib/module/skia/web/JsiSkFont.js +6 -0
  58. package/lib/module/skia/web/JsiSkFont.js.map +1 -1
  59. package/lib/module/skia/web/JsiSkMatrix.js +4 -0
  60. package/lib/module/skia/web/JsiSkMatrix.js.map +1 -1
  61. package/lib/module/values/api.js +0 -4
  62. package/lib/module/values/api.js.map +1 -1
  63. package/lib/module/values/hooks/useComputedValue.js +1 -1
  64. package/lib/module/values/hooks/useComputedValue.js.map +1 -1
  65. package/lib/module/views/SkiaView.web.js +27 -37
  66. package/lib/module/views/SkiaView.web.js.map +1 -1
  67. package/lib/module/web/LoadSkiaWeb.js +16 -0
  68. package/lib/module/web/LoadSkiaWeb.js.map +1 -0
  69. package/lib/module/web/WithSkiaWeb.js +23 -0
  70. package/lib/module/web/WithSkiaWeb.js.map +1 -0
  71. package/lib/module/web/index.js +2 -9
  72. package/lib/module/web/index.js.map +1 -1
  73. package/lib/typescript/jestSetup.d.ts +1 -0
  74. package/lib/typescript/src/animation/functions/interpolate.d.ts +6 -0
  75. package/lib/typescript/src/animation/functions/interpolatePaths.d.ts +3 -1
  76. package/lib/typescript/src/mock/index.d.ts +11 -42
  77. package/lib/typescript/src/renderer/Canvas.d.ts +1 -1
  78. package/lib/typescript/src/renderer/processors/Transform.d.ts +2 -2
  79. package/lib/typescript/src/skia/types/Font/Font.d.ts +6 -0
  80. package/lib/typescript/src/skia/types/Matrix.d.ts +6 -2
  81. package/lib/typescript/src/skia/types/Typeface/Typeface.d.ts +1 -4
  82. package/lib/typescript/src/skia/web/JsiSkFont.d.ts +1 -0
  83. package/lib/typescript/src/skia/web/JsiSkMatrix.d.ts +1 -0
  84. package/lib/typescript/src/values/api.d.ts +0 -1
  85. package/lib/typescript/src/views/SkiaView.web.d.ts +4 -6
  86. package/lib/typescript/src/web/LoadSkiaWeb.d.ts +6 -0
  87. package/lib/typescript/src/web/WithSkiaWeb.d.ts +12 -0
  88. package/lib/typescript/src/web/index.d.ts +2 -5
  89. package/package.json +7 -3
  90. package/scripts/setup-canvaskit.js +74 -0
  91. package/src/animation/functions/interpolate.ts +4 -2
  92. package/src/animation/functions/interpolateColors.ts +1 -1
  93. package/src/animation/functions/interpolatePaths.ts +59 -10
  94. package/src/mock/index.ts +103 -149
  95. package/src/renderer/components/Group.tsx +1 -1
  96. package/src/renderer/processors/Transform.ts +7 -10
  97. package/src/skia/core/Data.ts +7 -8
  98. package/src/skia/types/Font/Font.ts +7 -0
  99. package/src/skia/types/Matrix.ts +19 -3
  100. package/src/skia/types/Typeface/Typeface.ts +1 -4
  101. package/src/skia/web/JsiSkFont.ts +6 -0
  102. package/src/skia/web/JsiSkMatrix.ts +4 -0
  103. package/src/values/api.ts +0 -2
  104. package/src/values/hooks/useComputedValue.ts +1 -1
  105. package/src/views/SkiaView.web.tsx +36 -43
  106. package/src/web/LoadSkiaWeb.tsx +24 -0
  107. package/src/web/WithSkiaWeb.tsx +37 -0
  108. package/src/web/index.ts +2 -15
@@ -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
 
@@ -32,20 +32,19 @@ const loadDataCollection = <T>(
32
32
  ): Promise<(T | null)[]> =>
33
33
  Promise.all(sources.map((source) => loadData(source, factory, onError)));
34
34
 
35
- const loadData = <T>(
35
+ const loadData = async <T>(
36
36
  source: DataSource,
37
37
  factory: (data: SkData) => T,
38
38
  onError?: (err: Error) => void
39
39
  ): Promise<T | null> => {
40
- if (source instanceof Uint8Array) {
41
- return new Promise((resolve) =>
42
- resolve(factoryWrapper(Skia.Data.fromBytes(source), factory, onError))
43
- );
40
+ if (source === null) {
41
+ return null;
42
+ } else if (source instanceof Uint8Array) {
43
+ return factoryWrapper(Skia.Data.fromBytes(source), factory, onError);
44
44
  } else {
45
45
  const uri = typeof source === "string" ? source : resolveAsset(source);
46
- return Skia.Data.fromURI(uri).then((d) =>
47
- factoryWrapper(d, factory, onError)
48
- );
46
+ const d = await Skia.Data.fromURI(uri);
47
+ return factoryWrapper(d, factory, onError);
49
48
  }
50
49
  };
51
50
 
@@ -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,
@@ -8,15 +9,19 @@ export enum MatrixIndex {
8
9
  TransY = 5,
9
10
  Persp0 = 6,
10
11
  Persp1 = 7,
11
- persp2 = 8,
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
+ };
@@ -1,6 +1,3 @@
1
1
  import type { SkJSIInstance } from "../JsiInstance";
2
2
 
3
- export interface SkTypeface extends SkJSIInstance<"Typeface"> {
4
- readonly bold: boolean;
5
- readonly italic: boolean;
6
- }
3
+ export type SkTypeface = SkJSIInstance<"Typeface">;
@@ -27,6 +27,12 @@ Clients should use "Font.getGlyphWidths" instead (the latter does no shaping)`
27
27
  return new JsiSkRect(this.CanvasKit, this.CanvasKit.XYWHRect(0, 0, 0, 0));
28
28
  }
29
29
 
30
+ getTextWidth(text: string, paint?: SkPaint | undefined) {
31
+ const ids = this.getGlyphIDs(text);
32
+ const widths = this.getGlyphWidths(ids, paint);
33
+ return widths.reduce((a, b) => a + b, 0);
34
+ }
35
+
30
36
  getMetrics() {
31
37
  const result = this.ref.getMetrics();
32
38
  return {
@@ -51,4 +51,8 @@ export class JsiSkMatrix
51
51
  )
52
52
  );
53
53
  }
54
+
55
+ identity() {
56
+ this.ref.set(this.CanvasKit.Matrix.identity());
57
+ }
54
58
  }
package/src/values/api.ts CHANGED
@@ -6,5 +6,3 @@ declare global {
6
6
 
7
7
  const { SkiaValueApi } = global;
8
8
  export const ValueApi = SkiaValueApi;
9
-
10
- export const { createValue, createComputedValue } = ValueApi;
@@ -1,7 +1,7 @@
1
1
  import { useMemo } from "react";
2
2
 
3
3
  import { ValueApi } from "../api";
4
- import { isValue } from "../../renderer/processors";
4
+ import { isValue } from "../../renderer/processors/Animations";
5
5
 
6
6
  /**
7
7
  * Creates a new computed value - a value that will calculate its value depending
@@ -36,29 +36,32 @@ export class SkiaView extends React.Component<
36
36
  }
37
37
 
38
38
  private onLayout(evt: LayoutChangeEvent) {
39
- this.setState({
40
- width: evt.nativeEvent.layout.width,
41
- height: evt.nativeEvent.layout.height,
42
- });
43
- // Reset canvas / surface on layout change
44
- if (this._canvasRef.current) {
45
- // Create surface
46
- this._surface = new JsiSkSurface(
47
- global.CanvasKit,
48
- global.CanvasKit.MakeCanvasSurface(this._canvasRef.current)!
49
- );
50
- // Get canvas and repaint
51
- if (this._surface) {
52
- this._canvas = this._surface.getCanvas();
53
- this.requestRedraw();
54
- this.redraw();
39
+ this.setState(
40
+ {
41
+ width: evt.nativeEvent.layout.width,
42
+ height: evt.nativeEvent.layout.height,
43
+ },
44
+ () => {
45
+ // Reset canvas / surface on layout change
46
+ if (this._canvasRef.current) {
47
+ // Create surface
48
+ this._surface = new JsiSkSurface(
49
+ global.CanvasKit,
50
+ global.CanvasKit.MakeWebGLCanvasSurface(this._canvasRef.current)!
51
+ );
52
+ // Get canvas and repaint
53
+ if (this._surface) {
54
+ this._canvas = this._surface.getCanvas();
55
+ this.redraw();
56
+ }
57
+ }
55
58
  }
56
- }
59
+ );
57
60
  }
58
61
 
59
62
  componentDidMount() {
60
63
  // Start render loop
61
- this.redraw();
64
+ this.tick();
62
65
  }
63
66
 
64
67
  componentWillUnmount() {
@@ -80,7 +83,7 @@ export class SkiaView extends React.Component<
80
83
  /**
81
84
  * Sends a redraw request to the native SkiaView.
82
85
  */
83
- private redraw() {
86
+ private tick() {
84
87
  if (this._mode === "continuous" || this._redrawRequests > 0) {
85
88
  this._redrawRequests = 0;
86
89
  if (
@@ -95,7 +98,7 @@ export class SkiaView extends React.Component<
95
98
  height: this.state.height,
96
99
  width: this.state.width,
97
100
  timestamp: Date.now(),
98
- touches: [touches],
101
+ touches: touches.map((t) => [t]),
99
102
  };
100
103
  this.props.onDraw && this.props.onDraw(this._canvas!, info);
101
104
  this._surface?.ref.flush();
@@ -103,11 +106,11 @@ export class SkiaView extends React.Component<
103
106
  }
104
107
  // Always request a new redraw as long as we're not unmounted
105
108
  if (!this._unmounted) {
106
- requestAnimationFrame(this.redraw.bind(this));
109
+ requestAnimationFrame(this.tick.bind(this));
107
110
  }
108
111
  }
109
112
 
110
- public requestRedraw() {
113
+ public redraw() {
111
114
  this._redrawRequests++;
112
115
  }
113
116
 
@@ -122,7 +125,7 @@ export class SkiaView extends React.Component<
122
125
  */
123
126
  public setDrawMode(mode: DrawMode) {
124
127
  this._mode = mode;
125
- this.redraw();
128
+ this.tick();
126
129
  }
127
130
 
128
131
  /**
@@ -137,7 +140,7 @@ export class SkiaView extends React.Component<
137
140
  _values.forEach((v) => {
138
141
  this._unsubscriptions.push(
139
142
  v.addListener(() => {
140
- this.requestRedraw();
143
+ this.redraw();
141
144
  })
142
145
  );
143
146
  });
@@ -152,23 +155,11 @@ export class SkiaView extends React.Component<
152
155
  type: touchType,
153
156
  timestamp: Date.now(),
154
157
  });
155
- this.requestRedraw();
156
- }
157
-
158
- handleTouchStart(evt: PointerEvent) {
159
- this.handleTouchEvent(evt, TouchType.Start);
160
- }
161
-
162
- handleTouchMove(evt: PointerEvent) {
163
- this.handleTouchEvent(evt, TouchType.Active);
164
- }
165
-
166
- handleTouchEnd(evt: PointerEvent) {
167
- this.handleTouchEvent(evt, TouchType.Cancelled);
158
+ this.redraw();
168
159
  }
169
160
 
170
- handleTouchCancel(evt: PointerEvent) {
171
- this.handleTouchEvent(evt, TouchType.End);
161
+ createTouchHandler(touchType: TouchType) {
162
+ return (evt: PointerEvent) => this.handleTouchEvent(evt, touchType);
172
163
  }
173
164
 
174
165
  render() {
@@ -179,10 +170,12 @@ export class SkiaView extends React.Component<
179
170
  ref={this._canvasRef}
180
171
  width={this.state.width}
181
172
  height={this.state.height}
182
- onPointerDown={this.handleTouchStart.bind(this)}
183
- onPointerMove={this.handleTouchMove.bind(this)}
184
- onPointerUp={this.handleTouchEnd.bind(this)}
185
- onPointerCancel={this.handleTouchCancel.bind(this)}
173
+ onPointerDown={this.createTouchHandler(TouchType.Start)}
174
+ onPointerMove={this.createTouchHandler(TouchType.Active)}
175
+ onPointerUp={this.createTouchHandler(TouchType.End)}
176
+ onPointerCancel={this.createTouchHandler(TouchType.Cancelled)}
177
+ onPointerLeave={this.createTouchHandler(TouchType.End)}
178
+ onPointerOut={this.createTouchHandler(TouchType.End)}
186
179
  />
187
180
  </View>
188
181
  );
@@ -0,0 +1,24 @@
1
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
+ // @ts-expect-error
3
+ import CanvasKitInit from "canvaskit-wasm/bin/full/canvaskit";
4
+ import type {
5
+ CanvasKit as CanvasKitType,
6
+ CanvasKitInitOptions,
7
+ } from "canvaskit-wasm";
8
+
9
+ declare global {
10
+ var CanvasKit: CanvasKitType;
11
+ }
12
+
13
+ export const LoadSkiaWeb = async (opts?: CanvasKitInitOptions) => {
14
+ if (global.CanvasKit !== undefined) {
15
+ return;
16
+ }
17
+ const CanvasKit = await CanvasKitInit(opts);
18
+ // The CanvasKit API is stored on the global object and used
19
+ // to create the JsiSKApi in the Skia.web.ts file.
20
+ global.CanvasKit = CanvasKit;
21
+ };
22
+
23
+ // We keep this function for backward compatibility
24
+ export const LoadSkia = LoadSkiaWeb;
@@ -0,0 +1,37 @@
1
+ import type { ComponentProps, ComponentType } from "react";
2
+ import React, { useMemo, lazy, Suspense } from "react";
3
+ import { Platform } from "react-native";
4
+
5
+ import { LoadSkiaWeb } from "./LoadSkiaWeb";
6
+
7
+ interface WithSkiaProps {
8
+ fallback?: ComponentProps<typeof Suspense>["fallback"];
9
+ getComponent: () => Promise<{ default: ComponentType }>;
10
+ opts?: Parameters<typeof LoadSkiaWeb>[0];
11
+ }
12
+
13
+ export const WithSkiaWeb = ({
14
+ getComponent,
15
+ fallback,
16
+ opts,
17
+ }: WithSkiaProps) => {
18
+ const Inner = useMemo(
19
+ () =>
20
+ lazy(async () => {
21
+ if (Platform.OS === "web") {
22
+ await LoadSkiaWeb(opts);
23
+ } else {
24
+ console.warn(
25
+ "<WithSkiaWeb /> is only necessary on web. Consider not using on native."
26
+ );
27
+ }
28
+ return getComponent();
29
+ }),
30
+ [getComponent, opts]
31
+ );
32
+ return (
33
+ <Suspense fallback={fallback ?? null}>
34
+ <Inner />
35
+ </Suspense>
36
+ );
37
+ };
package/src/web/index.ts CHANGED
@@ -1,15 +1,2 @@
1
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
- // @ts-expect-error
3
- import CanvasKitInit from "canvaskit-wasm/bin/full/canvaskit";
4
- import type { CanvasKit as CanvasKitType } from "canvaskit-wasm";
5
-
6
- declare global {
7
- var CanvasKit: CanvasKitType;
8
- }
9
-
10
- export const LoadSkia = async () => {
11
- const CanvasKit = await CanvasKitInit();
12
- // The CanvasKit API is stored on the global object and used
13
- // to create the JsiSKApi in the Skia.web.ts file.
14
- global.CanvasKit = CanvasKit;
15
- };
1
+ export * from "./LoadSkiaWeb";
2
+ export * from "./WithSkiaWeb";