@shopify/react-native-skia 0.1.134 → 0.1.138

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