@shopify/react-native-skia 0.1.142 → 0.1.146

Sign up to get free protection for your applications and to get access to all the features.
Files changed (227) hide show
  1. package/cpp/api/JsiSkContourMeasure.h +4 -4
  2. package/cpp/api/JsiSkDataFactory.h +3 -3
  3. package/cpp/api/JsiSkFont.h +1 -1
  4. package/cpp/api/JsiSkPaint.h +6 -0
  5. package/cpp/api/JsiSkPathFactory.h +2 -2
  6. package/cpp/api/JsiSkPicture.h +7 -1
  7. package/cpp/api/JsiSkPictureFactory.h +1 -1
  8. package/cpp/api/JsiSkRuntimeEffect.h +6 -6
  9. package/cpp/api/JsiSkRuntimeEffectFactory.h +1 -1
  10. package/cpp/jsi/JsiSimpleValueWrapper.h +27 -27
  11. package/cpp/jsi/JsiValueWrapper.h +127 -0
  12. package/cpp/rnskia/RNSkDrawView.cpp +44 -20
  13. package/cpp/rnskia/RNSkDrawView.h +18 -20
  14. package/cpp/rnskia/RNSkJsiViewApi.h +180 -166
  15. package/cpp/rnskia/values/RNSkComputedValue.h +11 -11
  16. package/cpp/rnskia/values/RNSkReadonlyValue.h +19 -19
  17. package/cpp/rnskia/values/RNSkValue.h +13 -13
  18. package/cpp/utils/RNSkLog.h +4 -4
  19. package/lib/commonjs/renderer/Canvas.js +17 -7
  20. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  21. package/lib/commonjs/renderer/DependencyManager.js +144 -36
  22. package/lib/commonjs/renderer/DependencyManager.js.map +1 -1
  23. package/lib/commonjs/renderer/HostConfig.js +18 -2
  24. package/lib/commonjs/renderer/HostConfig.js.map +1 -1
  25. package/lib/commonjs/renderer/components/Blend.js +20 -5
  26. package/lib/commonjs/renderer/components/Blend.js.map +1 -1
  27. package/lib/commonjs/renderer/components/backdrop/BackdropFilter.js.map +1 -1
  28. package/lib/commonjs/renderer/components/imageFilters/Morphology.js +1 -1
  29. package/lib/commonjs/renderer/components/imageFilters/Morphology.js.map +1 -1
  30. package/lib/commonjs/renderer/components/imageFilters/Shadow.js +1 -1
  31. package/lib/commonjs/renderer/components/imageFilters/Shadow.js.map +1 -1
  32. package/lib/commonjs/renderer/nodes/Declaration.js +2 -3
  33. package/lib/commonjs/renderer/nodes/Declaration.js.map +1 -1
  34. package/lib/commonjs/renderer/nodes/Drawing.js +3 -7
  35. package/lib/commonjs/renderer/nodes/Drawing.js.map +1 -1
  36. package/lib/commonjs/renderer/nodes/Node.js +9 -7
  37. package/lib/commonjs/renderer/nodes/Node.js.map +1 -1
  38. package/lib/commonjs/renderer/processors/Animations/Animations.js +3 -22
  39. package/lib/commonjs/renderer/processors/Animations/Animations.js.map +1 -1
  40. package/lib/commonjs/skia/types/Paint/Paint.js.map +1 -1
  41. package/lib/commonjs/skia/web/Host.js +12 -21
  42. package/lib/commonjs/skia/web/Host.js.map +1 -1
  43. package/lib/commonjs/skia/web/JsiSkCanvas.js +46 -26
  44. package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
  45. package/lib/commonjs/skia/web/JsiSkColorFilterFactory.js +4 -4
  46. package/lib/commonjs/skia/web/JsiSkColorFilterFactory.js.map +1 -1
  47. package/lib/commonjs/skia/web/JsiSkFont.js +7 -3
  48. package/lib/commonjs/skia/web/JsiSkFont.js.map +1 -1
  49. package/lib/commonjs/skia/web/JsiSkImage.js +4 -2
  50. package/lib/commonjs/skia/web/JsiSkImage.js.map +1 -1
  51. package/lib/commonjs/skia/web/JsiSkImageFactory.js +4 -2
  52. package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
  53. package/lib/commonjs/skia/web/JsiSkImageFilterFactory.js +61 -19
  54. package/lib/commonjs/skia/web/JsiSkImageFilterFactory.js.map +1 -1
  55. package/lib/commonjs/skia/web/JsiSkMatrix.js +1 -1
  56. package/lib/commonjs/skia/web/JsiSkMatrix.js.map +1 -1
  57. package/lib/commonjs/skia/web/JsiSkPaint.js +19 -6
  58. package/lib/commonjs/skia/web/JsiSkPaint.js.map +1 -1
  59. package/lib/commonjs/skia/web/JsiSkPath.js +9 -55
  60. package/lib/commonjs/skia/web/JsiSkPath.js.map +1 -1
  61. package/lib/commonjs/skia/web/JsiSkPathEffectFactory.js +7 -3
  62. package/lib/commonjs/skia/web/JsiSkPathEffectFactory.js.map +1 -1
  63. package/lib/commonjs/skia/web/JsiSkPathFactory.js +1 -1
  64. package/lib/commonjs/skia/web/JsiSkPathFactory.js.map +1 -1
  65. package/lib/commonjs/skia/web/JsiSkPicture.js +5 -1
  66. package/lib/commonjs/skia/web/JsiSkPicture.js.map +1 -1
  67. package/lib/commonjs/skia/web/JsiSkPictureRecorder.js +3 -1
  68. package/lib/commonjs/skia/web/JsiSkPictureRecorder.js.map +1 -1
  69. package/lib/commonjs/skia/web/JsiSkPoint.js +9 -1
  70. package/lib/commonjs/skia/web/JsiSkPoint.js.map +1 -1
  71. package/lib/commonjs/skia/web/JsiSkRRect.js +1 -1
  72. package/lib/commonjs/skia/web/JsiSkRRect.js.map +1 -1
  73. package/lib/commonjs/skia/web/JsiSkRSXform.js.map +1 -1
  74. package/lib/commonjs/skia/web/JsiSkRect.js +1 -1
  75. package/lib/commonjs/skia/web/JsiSkRect.js.map +1 -1
  76. package/lib/commonjs/skia/web/JsiSkRuntimeEffect.js +4 -2
  77. package/lib/commonjs/skia/web/JsiSkRuntimeEffect.js.map +1 -1
  78. package/lib/commonjs/skia/web/JsiSkShaderFactory.js +10 -6
  79. package/lib/commonjs/skia/web/JsiSkShaderFactory.js.map +1 -1
  80. package/lib/commonjs/skia/web/JsiSkSurface.js +3 -1
  81. package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
  82. package/lib/commonjs/skia/web/JsiSkTextBlobFactory.js +8 -4
  83. package/lib/commonjs/skia/web/JsiSkTextBlobFactory.js.map +1 -1
  84. package/lib/commonjs/skia/web/JsiSkTypefaceFactory.js +1 -1
  85. package/lib/commonjs/skia/web/JsiSkTypefaceFactory.js.map +1 -1
  86. package/lib/commonjs/skia/web/JsiSkia.js +12 -6
  87. package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
  88. package/lib/commonjs/views/SkiaView.js +11 -27
  89. package/lib/commonjs/views/SkiaView.js.map +1 -1
  90. package/lib/commonjs/views/types.js.map +1 -1
  91. package/lib/module/renderer/Canvas.js +17 -6
  92. package/lib/module/renderer/Canvas.js.map +1 -1
  93. package/lib/module/renderer/DependencyManager.js +140 -33
  94. package/lib/module/renderer/DependencyManager.js.map +1 -1
  95. package/lib/module/renderer/HostConfig.js +18 -2
  96. package/lib/module/renderer/HostConfig.js.map +1 -1
  97. package/lib/module/renderer/components/Blend.js +21 -5
  98. package/lib/module/renderer/components/Blend.js.map +1 -1
  99. package/lib/module/renderer/components/backdrop/BackdropFilter.js.map +1 -1
  100. package/lib/module/renderer/components/imageFilters/Morphology.js +1 -1
  101. package/lib/module/renderer/components/imageFilters/Morphology.js.map +1 -1
  102. package/lib/module/renderer/components/imageFilters/Shadow.js +1 -1
  103. package/lib/module/renderer/components/imageFilters/Shadow.js.map +1 -1
  104. package/lib/module/renderer/nodes/Declaration.js +3 -4
  105. package/lib/module/renderer/nodes/Declaration.js.map +1 -1
  106. package/lib/module/renderer/nodes/Drawing.js +3 -6
  107. package/lib/module/renderer/nodes/Drawing.js.map +1 -1
  108. package/lib/module/renderer/nodes/Node.js +9 -7
  109. package/lib/module/renderer/nodes/Node.js.map +1 -1
  110. package/lib/module/renderer/processors/Animations/Animations.js +1 -16
  111. package/lib/module/renderer/processors/Animations/Animations.js.map +1 -1
  112. package/lib/module/skia/types/Paint/Paint.js.map +1 -1
  113. package/lib/module/skia/web/Host.js +9 -9
  114. package/lib/module/skia/web/Host.js.map +1 -1
  115. package/lib/module/skia/web/JsiSkCanvas.js +37 -27
  116. package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
  117. package/lib/module/skia/web/JsiSkColorFilterFactory.js +5 -5
  118. package/lib/module/skia/web/JsiSkColorFilterFactory.js.map +1 -1
  119. package/lib/module/skia/web/JsiSkFont.js +6 -4
  120. package/lib/module/skia/web/JsiSkFont.js.map +1 -1
  121. package/lib/module/skia/web/JsiSkImage.js +4 -3
  122. package/lib/module/skia/web/JsiSkImage.js.map +1 -1
  123. package/lib/module/skia/web/JsiSkImageFactory.js +4 -3
  124. package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
  125. package/lib/module/skia/web/JsiSkImageFilterFactory.js +61 -20
  126. package/lib/module/skia/web/JsiSkImageFilterFactory.js.map +1 -1
  127. package/lib/module/skia/web/JsiSkMatrix.js +2 -2
  128. package/lib/module/skia/web/JsiSkMatrix.js.map +1 -1
  129. package/lib/module/skia/web/JsiSkPaint.js +15 -7
  130. package/lib/module/skia/web/JsiSkPaint.js.map +1 -1
  131. package/lib/module/skia/web/JsiSkPath.js +9 -57
  132. package/lib/module/skia/web/JsiSkPath.js.map +1 -1
  133. package/lib/module/skia/web/JsiSkPathEffectFactory.js +6 -4
  134. package/lib/module/skia/web/JsiSkPathEffectFactory.js.map +1 -1
  135. package/lib/module/skia/web/JsiSkPathFactory.js +2 -2
  136. package/lib/module/skia/web/JsiSkPathFactory.js.map +1 -1
  137. package/lib/module/skia/web/JsiSkPicture.js +4 -2
  138. package/lib/module/skia/web/JsiSkPicture.js.map +1 -1
  139. package/lib/module/skia/web/JsiSkPictureRecorder.js +3 -2
  140. package/lib/module/skia/web/JsiSkPictureRecorder.js.map +1 -1
  141. package/lib/module/skia/web/JsiSkPoint.js +10 -2
  142. package/lib/module/skia/web/JsiSkPoint.js.map +1 -1
  143. package/lib/module/skia/web/JsiSkRRect.js +2 -2
  144. package/lib/module/skia/web/JsiSkRRect.js.map +1 -1
  145. package/lib/module/skia/web/JsiSkRSXform.js.map +1 -1
  146. package/lib/module/skia/web/JsiSkRect.js +2 -2
  147. package/lib/module/skia/web/JsiSkRect.js.map +1 -1
  148. package/lib/module/skia/web/JsiSkRuntimeEffect.js +4 -3
  149. package/lib/module/skia/web/JsiSkRuntimeEffect.js.map +1 -1
  150. package/lib/module/skia/web/JsiSkShaderFactory.js +9 -7
  151. package/lib/module/skia/web/JsiSkShaderFactory.js.map +1 -1
  152. package/lib/module/skia/web/JsiSkSurface.js +3 -2
  153. package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
  154. package/lib/module/skia/web/JsiSkTextBlobFactory.js +7 -5
  155. package/lib/module/skia/web/JsiSkTextBlobFactory.js.map +1 -1
  156. package/lib/module/skia/web/JsiSkTypefaceFactory.js +2 -2
  157. package/lib/module/skia/web/JsiSkTypefaceFactory.js.map +1 -1
  158. package/lib/module/skia/web/JsiSkia.js +10 -5
  159. package/lib/module/skia/web/JsiSkia.js.map +1 -1
  160. package/lib/module/views/SkiaView.js +11 -26
  161. package/lib/module/views/SkiaView.js.map +1 -1
  162. package/lib/module/views/types.js.map +1 -1
  163. package/lib/typescript/src/renderer/Canvas.d.ts +1 -1
  164. package/lib/typescript/src/renderer/DependencyManager.d.ts +40 -14
  165. package/lib/typescript/src/renderer/nodes/Declaration.d.ts +2 -2
  166. package/lib/typescript/src/renderer/nodes/Drawing.d.ts +2 -2
  167. package/lib/typescript/src/renderer/nodes/Node.d.ts +3 -2
  168. package/lib/typescript/src/renderer/processors/Animations/Animations.d.ts +0 -1
  169. package/lib/typescript/src/skia/types/Paint/Paint.d.ts +5 -0
  170. package/lib/typescript/src/skia/types/Picture/Picture.d.ts +2 -1
  171. package/lib/typescript/src/skia/web/Host.d.ts +6 -8
  172. package/lib/typescript/src/skia/web/JsiSkImageFilterFactory.d.ts +8 -8
  173. package/lib/typescript/src/skia/web/JsiSkPaint.d.ts +1 -0
  174. package/lib/typescript/src/skia/web/JsiSkPoint.d.ts +3 -2
  175. package/lib/typescript/src/skia/web/JsiSkRRect.d.ts +2 -2
  176. package/lib/typescript/src/skia/web/JsiSkRSXform.d.ts +1 -2
  177. package/lib/typescript/src/skia/web/JsiSkRect.d.ts +2 -2
  178. package/lib/typescript/src/skia/web/JsiSkTextBlobFactory.d.ts +2 -1
  179. package/lib/typescript/src/views/SkiaView.d.ts +1 -11
  180. package/lib/typescript/src/views/types.d.ts +5 -5
  181. package/libs/ios/libskia.xcframework/Info.plist +5 -5
  182. package/libs/ios/libskia.xcframework/ios-arm64_arm64e/libskia.a +0 -0
  183. package/libs/ios/libskia.xcframework/ios-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  184. package/libs/ios/libskshaper.xcframework/ios-arm64_arm64e/libskshaper.a +0 -0
  185. package/libs/ios/libskshaper.xcframework/ios-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  186. package/libs/ios/libsvg.xcframework/ios-arm64_arm64e/libsvg.a +0 -0
  187. package/libs/ios/libsvg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  188. package/package.json +2 -2
  189. package/src/renderer/Canvas.tsx +19 -7
  190. package/src/renderer/DependencyManager.tsx +170 -39
  191. package/src/renderer/HostConfig.ts +12 -2
  192. package/src/renderer/components/Blend.tsx +25 -5
  193. package/src/renderer/components/backdrop/BackdropFilter.tsx +1 -1
  194. package/src/renderer/components/imageFilters/Morphology.tsx +2 -2
  195. package/src/renderer/components/imageFilters/Shadow.tsx +2 -2
  196. package/src/renderer/nodes/Declaration.tsx +6 -8
  197. package/src/renderer/nodes/Drawing.tsx +5 -7
  198. package/src/renderer/nodes/Node.ts +11 -9
  199. package/src/renderer/processors/Animations/Animations.ts +2 -15
  200. package/src/skia/types/Paint/Paint.ts +6 -0
  201. package/src/skia/types/Picture/Picture.ts +2 -1
  202. package/src/skia/web/Host.ts +12 -22
  203. package/src/skia/web/JsiSkCanvas.ts +78 -47
  204. package/src/skia/web/JsiSkColorFilterFactory.ts +15 -5
  205. package/src/skia/web/JsiSkFont.ts +11 -4
  206. package/src/skia/web/JsiSkImage.ts +4 -3
  207. package/src/skia/web/JsiSkImageFactory.ts +6 -3
  208. package/src/skia/web/JsiSkImageFilterFactory.ts +124 -52
  209. package/src/skia/web/JsiSkMatrix.ts +4 -2
  210. package/src/skia/web/JsiSkPaint.ts +15 -7
  211. package/src/skia/web/JsiSkPath.ts +16 -51
  212. package/src/skia/web/JsiSkPathEffectFactory.ts +10 -5
  213. package/src/skia/web/JsiSkPathFactory.ts +3 -3
  214. package/src/skia/web/JsiSkPicture.ts +5 -3
  215. package/src/skia/web/JsiSkPictureRecorder.ts +3 -2
  216. package/src/skia/web/JsiSkPoint.ts +12 -2
  217. package/src/skia/web/JsiSkRRect.ts +5 -2
  218. package/src/skia/web/JsiSkRSXform.ts +1 -1
  219. package/src/skia/web/JsiSkRect.ts +2 -2
  220. package/src/skia/web/JsiSkRuntimeEffect.ts +9 -4
  221. package/src/skia/web/JsiSkShaderFactory.ts +24 -15
  222. package/src/skia/web/JsiSkSurface.ts +7 -2
  223. package/src/skia/web/JsiSkTextBlobFactory.ts +14 -8
  224. package/src/skia/web/JsiSkTypefaceFactory.tsx +4 -2
  225. package/src/skia/web/JsiSkia.ts +17 -5
  226. package/src/views/SkiaView.tsx +17 -28
  227. package/src/views/types.ts +7 -6
@@ -1,62 +1,193 @@
1
- import type { RefObject } from "react";
2
-
3
- import type { SkiaView } from "../views";
4
1
  import type { SkiaValue } from "../values";
5
2
 
6
- import { isSelector, isValue } from "./processors";
7
3
  import type { Node } from "./nodes";
4
+ import type { AnimatedProps } from "./processors";
5
+ import { isSelector, isValue } from "./processors";
6
+ import { mapKeys } from "./typeddash";
8
7
 
9
8
  type Unsubscribe = () => void;
10
- type Props = { [key: string]: unknown };
9
+ type Mutator = (value: unknown) => void;
10
+
11
+ type SubscriptionState = {
12
+ nodes: Map<Node, Mutator[]>;
13
+ unsubscribe: null | Unsubscribe;
14
+ };
11
15
 
12
16
  export class DependencyManager {
13
- ref: RefObject<SkiaView>;
14
- subscriptions: Map<
15
- Node,
16
- { values: SkiaValue<unknown>[]; unsubscribe: null | Unsubscribe }
17
- > = new Map();
18
-
19
- constructor(ref: RefObject<SkiaView>) {
20
- this.ref = ref;
21
- }
17
+ registerValues: (values: Array<SkiaValue<unknown>>) => () => void;
18
+ subscriptions: Map<SkiaValue<unknown>, SubscriptionState> = new Map();
19
+ unregisterDependantValues: null | Unsubscribe = null;
22
20
 
23
- unSubscribeNode(node: Node) {
24
- const subscription = this.subscriptions.get(node);
25
- if (subscription && subscription.unsubscribe) {
26
- subscription.unsubscribe();
27
- }
28
- this.subscriptions.delete(node);
21
+ constructor(
22
+ registerValues: (values: Array<SkiaValue<unknown>>) => () => void
23
+ ) {
24
+ this.registerValues = registerValues;
29
25
  }
30
26
 
31
- subscribeNode(node: Node, props: Props) {
32
- const values = Object.values(props)
33
- .filter((v) => isValue(v) || isSelector(v))
34
- .map((v) => (isSelector(v) ? v.value : (v as SkiaValue<unknown>)));
27
+ /**
28
+ * Call to unsubscribe all value listeners from the given node based
29
+ * on the current list of subscriptions for the node. This function
30
+ * is typically called when the node is unmounted or when one or more
31
+ * properties have changed.
32
+ * @param node Node to unsubscribe value listeners from
33
+ */
34
+ unsubscribeNode(node: Node) {
35
+ const subscriptions = Array.from(this.subscriptions.values()).filter((p) =>
36
+ p.nodes.has(node)
37
+ );
35
38
 
36
- if (values.length > 0) {
37
- this.subscriptions.set(node, { values, unsubscribe: null });
39
+ if (subscriptions) {
40
+ subscriptions.forEach((si) => {
41
+ // Delete node from subscription
42
+ si.nodes.delete(node);
43
+
44
+ // Remove subscription if there are no listeneres left on the value
45
+ if (si.nodes.size === 0) {
46
+ // There are no more nodes subscribing to this value, we can call
47
+ // unsubscribe on it.
48
+ if (!si.unsubscribe) {
49
+ throw new Error("Failed to unsubscribe to value subscription");
50
+ }
51
+ si.unsubscribe && si.unsubscribe();
52
+
53
+ // Remove from subscription states as well
54
+ const element = Array.from(this.subscriptions.entries()).find(
55
+ ([_, sub]) => sub === si
56
+ );
57
+ if (!element) {
58
+ throw new Error("Failed to find value subscription");
59
+ }
60
+ if (!this.subscriptions.delete(element[0])) {
61
+ throw new Error("Failed to delete value subscription");
62
+ }
63
+ }
64
+ });
38
65
  }
39
66
  }
40
67
 
41
- subscribe() {
42
- if (this.ref.current === null) {
43
- throw new Error("Canvas ref is not set");
68
+ /**
69
+ * Adds listeners to the provided values so that the node is notified
70
+ * when a value changes. This is done in an optimized way so that this
71
+ * class only needs to listen to the value once and then forwards the
72
+ * change to the node and its listener. This method is typically called
73
+ * when the node is mounted and when one or more props on the node changes.
74
+ * @param node Node to subscribe to value changes for
75
+ * @param props Node's properties
76
+ * @param onResolveProp Callback when a property value changes
77
+ */
78
+ subscribeNode<P extends Record<string, unknown>>(
79
+ node: Node,
80
+ props: AnimatedProps<P>
81
+ ) {
82
+ // Get mutators from node's properties
83
+ const propSubscriptions = initializePropertySubscriptions(node, props);
84
+ if (propSubscriptions.length === 0) {
85
+ return;
44
86
  }
45
- this.subscriptions.forEach((subscription) => {
46
- if (subscription.unsubscribe === null) {
47
- subscription.unsubscribe = this.ref.current!.registerValues(
48
- subscription.values
49
- );
87
+
88
+ // Install all mutators for the node
89
+ propSubscriptions.forEach((ps) => {
90
+ // Do we already have a state for this SkiaValue
91
+ let subscriptionState = this.subscriptions.get(ps.value);
92
+ if (!subscriptionState) {
93
+ // Let's create a new subscription state for the skia value
94
+ subscriptionState = {
95
+ nodes: new Map(),
96
+ unsubscribe: null,
97
+ };
98
+ // Add single subscription to the new value
99
+ subscriptionState.unsubscribe = ps.value.addListener((v) => {
100
+ subscriptionState!.nodes.forEach((mutators) =>
101
+ mutators.forEach((m) => m(v))
102
+ );
103
+ });
104
+ this.subscriptions.set(ps.value, subscriptionState);
50
105
  }
106
+ // subscription mutators
107
+ subscriptionState.nodes.set(
108
+ node,
109
+ propSubscriptions
110
+ .filter((m) => m.value === ps.value)
111
+ .map((m) => m.mutator)
112
+ );
51
113
  });
52
114
  }
53
115
 
54
- unsubscribe() {
55
- this.subscriptions.forEach(({ unsubscribe }) => {
56
- if (unsubscribe) {
57
- unsubscribe();
58
- }
116
+ /**
117
+ * Called when the hosting container is mounted or updated. This ensures that we have
118
+ * a ref to the underlying SkiaView so that we can registers redraw listeners
119
+ * on values used in the current View automatically.
120
+ */
121
+ update() {
122
+ // Remove any previous registrations
123
+ if (this.unregisterDependantValues) {
124
+ this.unregisterDependantValues();
125
+ }
126
+
127
+ // Register redraw requests on the SkiaView for each unique value
128
+ this.unregisterDependantValues = this.registerValues(
129
+ Array.from(this.subscriptions.keys())
130
+ );
131
+ }
132
+
133
+ /**
134
+ * Called when the hosting container is unmounted or recreated. This ensures that we remove
135
+ * all subscriptions to Skia values so that we don't have any listeners left after
136
+ * the component is removed.
137
+ */
138
+ remove() {
139
+ // 1) Unregister redraw requests
140
+ if (this.unregisterDependantValues) {
141
+ this.unregisterDependantValues();
142
+ this.unregisterDependantValues = null;
143
+ }
144
+
145
+ // 2) Unregister nodes
146
+ Array.from(this.subscriptions.values()).forEach((si) => {
147
+ Array.from(si.nodes.keys()).forEach((node) => this.unsubscribeNode(node));
59
148
  });
149
+
150
+ // 3) Clear the rest of the subscriptions
60
151
  this.subscriptions.clear();
61
152
  }
62
153
  }
154
+
155
+ const initializePropertySubscriptions = <P,>(
156
+ node: Node<P>,
157
+ props: AnimatedProps<P>
158
+ ) => {
159
+ const nodePropSubscriptions: Array<{
160
+ value: SkiaValue<unknown>;
161
+ mutator: Mutator;
162
+ }> = [];
163
+
164
+ mapKeys(props).forEach((key) => {
165
+ const propvalue = props[key];
166
+
167
+ if (isValue(propvalue)) {
168
+ // Subscribe to changes
169
+ nodePropSubscriptions.push({
170
+ value: propvalue,
171
+ mutator: (v) => (node.resolvedProps[key] = v as P[typeof key]),
172
+ });
173
+ // Set initial value
174
+ node.resolvedProps[key] = (propvalue as SkiaValue<P[typeof key]>).current;
175
+ } else if (isSelector(propvalue)) {
176
+ // Subscribe to changes
177
+ nodePropSubscriptions.push({
178
+ value: propvalue.value,
179
+ mutator: (v) =>
180
+ (node.resolvedProps[key] = propvalue.selector(v) as P[typeof key]),
181
+ });
182
+ // Set initial value
183
+ node.resolvedProps[key] = propvalue.selector(
184
+ propvalue.value.current
185
+ ) as P[typeof key];
186
+ } else {
187
+ // Set initial value
188
+ node.resolvedProps[key] = propvalue as P[typeof key];
189
+ }
190
+ });
191
+
192
+ return nodePropSubscriptions;
193
+ };
@@ -101,7 +101,7 @@ const removeNode = (parent: Node, child: Node) => {
101
101
  bustBranchMemoization(parent);
102
102
  const index = parent.children.indexOf(child);
103
103
  parent.children.splice(index, 1);
104
- child.depMgr.unSubscribeNode(child);
104
+ child.depMgr.unsubscribeNode(child);
105
105
  // unsubscribe to all children as well
106
106
  for (const c of child.children) {
107
107
  removeNode(child, c);
@@ -265,7 +265,17 @@ export const skHostConfig: SkiaHostConfig = {
265
265
  return;
266
266
  }
267
267
  bustBranchMemoization(instance);
268
- instance.props = nextProps;
268
+ if (instance instanceof DrawingNode) {
269
+ const { onDraw, skipProcessing, ...props } = nextProps;
270
+ instance.props = props;
271
+ } else if (instance instanceof DeclarationNode) {
272
+ const { onDeclare, ...props } = nextProps;
273
+ instance.props = props;
274
+ } else {
275
+ throw new Error(
276
+ "Unsupported instance commitUpdate " + instance.constructor.name
277
+ );
278
+ }
269
279
  },
270
280
 
271
281
  commitTextUpdate: (
@@ -1,10 +1,21 @@
1
1
  import type { ReactNode } from "react";
2
2
  import React from "react";
3
3
 
4
+ import type { SkImageFilter, SkShader } from "../../skia/types";
4
5
  import { isImageFilter, BlendMode, isShader } from "../../skia/types";
5
6
  import { createDeclaration } from "../nodes";
6
7
  import type { AnimatedProps, SkEnum } from "../processors";
7
8
  import { enumKey } from "../processors/Paint";
9
+ import type { DeclarationResult } from "../nodes/Declaration";
10
+
11
+ const childrenAreImageFilters = (
12
+ children: DeclarationResult[]
13
+ ): children is SkImageFilter[] =>
14
+ children.every((child) => isImageFilter(child));
15
+
16
+ const childrenAreShaders = (
17
+ children: DeclarationResult[]
18
+ ): children is SkShader[] => children.every((child) => isShader(child));
8
19
 
9
20
  interface BlendProps {
10
21
  mode: SkEnum<typeof BlendMode>;
@@ -13,12 +24,21 @@ interface BlendProps {
13
24
 
14
25
  const onDeclare = createDeclaration<BlendProps>(
15
26
  ({ mode }, children, { Skia }) => {
16
- const [inner, outer] = children;
17
27
  const blend = BlendMode[enumKey(mode)];
18
- if (isImageFilter(outer) && isImageFilter(inner)) {
19
- return Skia.ImageFilter.MakeBlend(blend, outer, inner);
20
- } else if (isShader(outer) && isShader(inner)) {
21
- return Skia.Shader.MakeBlend(blend, outer, inner);
28
+ if (childrenAreImageFilters(children)) {
29
+ return children.reverse().reduce<SkImageFilter | null>((inner, outer) => {
30
+ if (inner === null) {
31
+ return outer;
32
+ }
33
+ return Skia.ImageFilter.MakeBlend(blend, outer, inner);
34
+ }, null);
35
+ } else if (childrenAreShaders(children)) {
36
+ return children.reverse().reduce<SkShader | null>((inner, outer) => {
37
+ if (inner === null) {
38
+ return outer;
39
+ }
40
+ return Skia.Shader.MakeBlend(blend, outer, inner);
41
+ }, null);
22
42
  }
23
43
  throw new Error("<Blend /> can only blend Shaders or ImageFilters");
24
44
  }
@@ -8,7 +8,7 @@ import { getInput } from "../imageFilters/getInput";
8
8
  import type { GroupProps } from "../Group";
9
9
  import { Group } from "../Group";
10
10
 
11
- const disableFilterMemoization = (children: Node<unknown>[]) => {
11
+ const disableFilterMemoization = (children: Node[]) => {
12
12
  children.forEach((child) => {
13
13
  child.memoizable = false;
14
14
  disableFilterMemoization(child.children);
@@ -18,8 +18,8 @@ const onDeclare = createDeclaration<MorphologyProps>(
18
18
  const r = processRadius(Skia, radius);
19
19
  const factory =
20
20
  operator === "dilate"
21
- ? Skia.ImageFilter.MakeDilate
22
- : Skia.ImageFilter.MakeErode;
21
+ ? Skia.ImageFilter.MakeDilate.bind(Skia.ImageFilter)
22
+ : Skia.ImageFilter.MakeErode.bind(Skia.ImageFilter);
23
23
  return factory(r.x, r.y, input);
24
24
  }
25
25
  );
@@ -30,8 +30,8 @@ const onDeclare = createDeclaration<ShadowProps>(
30
30
  factory = MakeInnerShadow.bind(null, Skia, shadowOnly);
31
31
  } else {
32
32
  factory = shadowOnly
33
- ? Skia.ImageFilter.MakeDropShadowOnly
34
- : Skia.ImageFilter.MakeDropShadow;
33
+ ? Skia.ImageFilter.MakeDropShadowOnly.bind(Skia.ImageFilter)
34
+ : Skia.ImageFilter.MakeDropShadow.bind(Skia.ImageFilter);
35
35
  }
36
36
  return factory(dx, dy, blur, blur, color, input);
37
37
  }
@@ -3,7 +3,7 @@ import { useCallback } from "react";
3
3
 
4
4
  import type { DrawingContext } from "../DrawingContext";
5
5
  import type { AnimatedProps } from "../processors";
6
- import { isAnimated, materialize } from "../processors";
6
+ import { isAnimated } from "../processors";
7
7
  import type { DependencyManager } from "../DependencyManager";
8
8
  import type { SkJSIInstance } from "../../skia/types";
9
9
 
@@ -28,9 +28,8 @@ export const useDeclaration = <P,>(
28
28
  // eslint-disable-next-line react-hooks/exhaustive-deps
29
29
  useCallback(cb, deps ?? []);
30
30
 
31
- export const isDeclarationNode = (
32
- node: Node
33
- ): node is DeclarationNode<unknown> => node instanceof DeclarationNode;
31
+ export const isDeclarationNode = <P,>(node: Node): node is DeclarationNode<P> =>
32
+ node instanceof DeclarationNode;
34
33
 
35
34
  export interface DeclarationProps<P> {
36
35
  onDeclare: DeclarationCallback<P>;
@@ -54,14 +53,13 @@ export class DeclarationNode<P> extends Node<P> {
54
53
  super.props = props;
55
54
  }
56
55
 
57
- get props() {
58
- return this._props;
56
+ get props(): P {
57
+ return this.resolvedProps;
59
58
  }
60
59
 
61
60
  draw(ctx: DrawingContext) {
62
61
  const children = this.visit(ctx);
63
- const props = materialize(this.props);
64
- const obj = this.onDeclare(props, children, ctx);
62
+ const obj = this.onDeclare(this.props, children, ctx);
65
63
  return obj;
66
64
  }
67
65
  }
@@ -3,7 +3,6 @@ import { useCallback } from "react";
3
3
 
4
4
  import type { DrawingContext } from "../DrawingContext";
5
5
  import type { AnimatedProps } from "../processors/Animations/Animations";
6
- import { materialize } from "../processors/Animations/Animations";
7
6
  import { isPaint } from "../../skia/types";
8
7
  import type { DependencyManager } from "../DependencyManager";
9
8
  import { processPaint } from "../processors";
@@ -25,8 +24,8 @@ export const useDrawing = <P,>(cb: OnDrawCallback<P>, deps?: DependencyList) =>
25
24
  // eslint-disable-next-line react-hooks/exhaustive-deps
26
25
  useCallback(cb, deps ?? []);
27
26
 
28
- export type DrawingProps<T> = {
29
- onDraw: DrawingCallback<T>;
27
+ export type DrawingProps<P> = {
28
+ onDraw: DrawingCallback<P>;
30
29
  skipProcessing?: boolean;
31
30
  children?: ReactNode | ReactNode[];
32
31
  };
@@ -47,20 +46,19 @@ export class DrawingNode<P> extends Node<P> {
47
46
  }
48
47
 
49
48
  draw(ctx: DrawingContext) {
50
- const drawingProps = materialize(this.props);
51
49
  if (this.skipProcessing) {
52
- this.onDraw(ctx, drawingProps, this);
50
+ this.onDraw(ctx, this.props, this);
53
51
  } else {
54
52
  const declarations = this.visit(ctx);
55
53
  const paint = processPaint(
56
54
  ctx.Skia,
57
55
  ctx.paint.copy(),
58
56
  ctx.opacity,
59
- drawingProps,
57
+ this.props,
60
58
  declarations
61
59
  );
62
60
  [paint, ...declarations.filter(isPaint)].forEach((currentPaint) => {
63
- this.onDraw({ ...ctx, paint: currentPaint }, drawingProps, this);
61
+ this.onDraw({ ...ctx, paint: currentPaint }, this.props, this);
64
62
  });
65
63
  }
66
64
  }
@@ -12,29 +12,31 @@ type DeclarationResult = SkJSIInstance<string> | null;
12
12
 
13
13
  export abstract class Node<P = unknown> {
14
14
  readonly children: Node[] = [];
15
- _props: AnimatedProps<P>;
15
+ // This cast is ok because we understand that the dependency manager will setup the initial props
16
+ resolvedProps: P = {} as P;
16
17
  memoizable = false;
17
18
  memoized: DeclarationResult | null = null;
18
19
  parent?: Node;
19
20
  depMgr: DependencyManager;
20
21
 
21
22
  constructor(depMgr: DependencyManager, props: AnimatedProps<P>) {
22
- this._props = props;
23
23
  this.depMgr = depMgr;
24
- this.depMgr.unSubscribeNode(this);
25
- this.depMgr.subscribeNode(this, props);
24
+ this.updatePropSubscriptions(props);
26
25
  }
27
26
 
28
27
  abstract draw(ctx: DrawingContext): void | DeclarationResult;
29
28
 
30
- set props(props: AnimatedProps<P>) {
31
- this.depMgr.unSubscribeNode(this);
29
+ updatePropSubscriptions(props: AnimatedProps<P>) {
32
30
  this.depMgr.subscribeNode(this, props);
33
- this._props = props;
34
31
  }
35
32
 
36
- get props() {
37
- return this._props;
33
+ set props(props: AnimatedProps<P>) {
34
+ this.depMgr.unsubscribeNode(this);
35
+ this.updatePropSubscriptions(props);
36
+ }
37
+
38
+ get props(): P {
39
+ return this.resolvedProps;
38
40
  }
39
41
 
40
42
  visit(ctx: DrawingContext, children?: Node[]) {
@@ -1,5 +1,4 @@
1
1
  import type { SkiaSelector, SkiaValue } from "../../../values";
2
- import { mapKeys } from "../../typeddash";
3
2
 
4
3
  export const isValue = (value: unknown): value is SkiaValue<unknown> => {
5
4
  if (value === undefined || value === null) {
@@ -37,28 +36,16 @@ export const isSelector = <T, R>(
37
36
 
38
37
  export const isAnimated = <T>(props: AnimatedProps<T>) => {
39
38
  for (const value of Object.values(props)) {
40
- if (isValue(value)) {
39
+ if (isValue(value) || isSelector(value)) {
41
40
  return true;
42
41
  }
43
42
  }
44
43
  return false;
45
44
  };
46
45
 
47
- export const materialize = <T>(props: AnimatedProps<T>) => {
48
- const result = { ...props };
49
- mapKeys(props).forEach((key) => {
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];
55
- }
56
- });
57
- return result as T;
58
- };
59
-
60
46
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
47
  export type AnimatedProp<T, P = any> = T | SkiaValue<T> | SkiaSelector<T, P>;
48
+
62
49
  export type AnimatedProps<T> = {
63
50
  [K in keyof T]: AnimatedProp<T[K]>;
64
51
  };
@@ -34,6 +34,12 @@ export interface SkPaint extends SkJSIInstance<"Paint"> {
34
34
  */
35
35
  copy(): SkPaint;
36
36
 
37
+ /**
38
+ * Sets all SkPaint contents to their initial values. This is equivalent to replacing
39
+ SkPaint with the result of SkPaint().
40
+ */
41
+ reset(): void;
42
+
37
43
  /**
38
44
  * Retrieves the alpha and RGB unpremultiplied. RGB are extended sRGB values
39
45
  * (sRGB gamut, and encoded with the sRGB transfer function).
@@ -3,8 +3,9 @@ import type { TileMode } from "../ImageFilter";
3
3
  import type { SkRect } from "../Rect";
4
4
  import type { SkShader } from "../Shader";
5
5
  import type { SkMatrix } from "../Matrix";
6
+ import type { SkJSIInstance } from "../JsiInstance";
6
7
 
7
- export interface SkPicture {
8
+ export interface SkPicture extends SkJSIInstance<"Picture"> {
8
9
  /**
9
10
  * Returns a new shader that will draw with this picture.
10
11
  *
@@ -1,11 +1,10 @@
1
- /* eslint-disable no-nested-ternary */
2
1
  import type { CanvasKit, EmbindEnumEntity } from "canvaskit-wasm";
3
2
 
4
3
  import type { SkJSIInstance } from "../types";
5
4
 
6
5
  export class NotImplementedOnRNWeb extends Error {
7
- constructor() {
8
- super("Not implemented on React Native Web");
6
+ constructor(msg?: string) {
7
+ super(msg ?? "Not implemented on React Native Web");
9
8
  }
10
9
  }
11
10
 
@@ -17,12 +16,12 @@ export abstract class Host {
17
16
  }
18
17
  }
19
18
 
20
- export abstract class HostObject<T, N extends string>
19
+ export abstract class BaseHostObject<T, N extends string>
21
20
  extends Host
22
21
  implements SkJSIInstance<N>
23
22
  {
24
23
  readonly __typename__: N;
25
- readonly ref: T;
24
+ ref: T;
26
25
 
27
26
  constructor(CanvasKit: CanvasKit, ref: T, typename: N) {
28
27
  super(CanvasKit);
@@ -31,23 +30,14 @@ export abstract class HostObject<T, N extends string>
31
30
  }
32
31
  }
33
32
 
34
- // eslint-disable-next-line @typescript-eslint/ban-types
35
- export type NonNullish = {};
36
-
37
- export const toOptionalValue = <T>(
38
- value: NonNullish | undefined | null
39
- ): T | undefined | null =>
40
- value === undefined ? undefined : value === null ? null : toValue(value);
41
-
42
- export const toUndefinedableValue = <T>(
43
- value: NonNullish | undefined
44
- ): T | undefined => (value === undefined ? undefined : toValue(value));
45
-
46
- export const toNullableValue = <T>(value: NonNullish | null): T | null =>
47
- value === null ? null : toValue(value);
48
-
49
- export const toValue = <T>(value: NonNullish): T =>
50
- (value as HostObject<T, string>).ref;
33
+ export abstract class HostObject<T, N extends string> extends BaseHostObject<
34
+ T,
35
+ N
36
+ > {
37
+ static fromValue<T>(value: SkJSIInstance<string>) {
38
+ return (value as HostObject<T, string>).ref;
39
+ }
40
+ }
51
41
 
52
42
  export const ckEnum = (value: number): EmbindEnumEntity => ({ value });
53
43
  export const optEnum = (