@shopify/react-native-skia 0.1.141 → 0.1.145

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 (282) hide show
  1. package/android/cpp/rnskia-android/RNSkDrawViewImpl.cpp +2 -2
  2. package/android/cpp/rnskia-android/RNSkDrawViewImpl.h +1 -1
  3. package/android/cpp/rnskia-android/SkiaOpenGLRenderer.cpp +15 -16
  4. package/android/cpp/rnskia-android/SkiaOpenGLRenderer.h +2 -2
  5. package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java +69 -27
  6. package/cpp/api/JsiSkPaint.h +6 -0
  7. package/cpp/api/JsiSkPathFactory.h +1 -1
  8. package/cpp/api/JsiSkPicture.h +7 -1
  9. package/cpp/rnskia/RNSkDrawView.cpp +66 -66
  10. package/cpp/rnskia/RNSkDrawView.h +22 -6
  11. package/cpp/rnskia/RNSkJsiViewApi.h +2 -2
  12. package/cpp/rnskia/values/RNSkComputedValue.h +10 -7
  13. package/cpp/rnskia/values/RNSkReadonlyValue.h +21 -2
  14. package/cpp/rnskia/values/RNSkValue.h +1 -0
  15. package/ios/RNSkia-iOS/RNSkDrawViewImpl.h +1 -1
  16. package/ios/RNSkia-iOS/RNSkDrawViewImpl.mm +2 -2
  17. package/ios/RNSkia-iOS/SkiaDrawView.mm +4 -0
  18. package/lib/commonjs/mock/index.js +3 -1
  19. package/lib/commonjs/mock/index.js.map +1 -1
  20. package/lib/commonjs/renderer/Canvas.js +17 -7
  21. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  22. package/lib/commonjs/renderer/DependencyManager.js +144 -36
  23. package/lib/commonjs/renderer/DependencyManager.js.map +1 -1
  24. package/lib/commonjs/renderer/HostConfig.js +1 -1
  25. package/lib/commonjs/renderer/HostConfig.js.map +1 -1
  26. package/lib/commonjs/renderer/components/Blend.js +20 -5
  27. package/lib/commonjs/renderer/components/Blend.js.map +1 -1
  28. package/lib/commonjs/renderer/components/backdrop/BackdropFilter.js.map +1 -1
  29. package/lib/commonjs/renderer/components/imageFilters/Morphology.js +1 -1
  30. package/lib/commonjs/renderer/components/imageFilters/Morphology.js.map +1 -1
  31. package/lib/commonjs/renderer/components/imageFilters/Shadow.js +1 -1
  32. package/lib/commonjs/renderer/components/imageFilters/Shadow.js.map +1 -1
  33. package/lib/commonjs/renderer/nodes/Declaration.js +2 -3
  34. package/lib/commonjs/renderer/nodes/Declaration.js.map +1 -1
  35. package/lib/commonjs/renderer/nodes/Drawing.js +3 -7
  36. package/lib/commonjs/renderer/nodes/Drawing.js.map +1 -1
  37. package/lib/commonjs/renderer/nodes/Node.js +9 -7
  38. package/lib/commonjs/renderer/nodes/Node.js.map +1 -1
  39. package/lib/commonjs/renderer/processors/Animations/Animations.js +14 -20
  40. package/lib/commonjs/renderer/processors/Animations/Animations.js.map +1 -1
  41. package/lib/commonjs/skia/core/Data.js +10 -22
  42. package/lib/commonjs/skia/core/Data.js.map +1 -1
  43. package/lib/commonjs/skia/core/Font.js +2 -3
  44. package/lib/commonjs/skia/core/Font.js.map +1 -1
  45. package/lib/commonjs/skia/core/Image.js.map +1 -1
  46. package/lib/commonjs/skia/core/SVG.js.map +1 -1
  47. package/lib/commonjs/skia/core/Typeface.js.map +1 -1
  48. package/lib/commonjs/skia/types/Data/Data.js +5 -0
  49. package/lib/commonjs/skia/types/Data/Data.js.map +1 -1
  50. package/lib/commonjs/skia/types/Paint/Paint.js.map +1 -1
  51. package/lib/commonjs/skia/web/Host.js +12 -21
  52. package/lib/commonjs/skia/web/Host.js.map +1 -1
  53. package/lib/commonjs/skia/web/JsiSkCanvas.js +50 -28
  54. package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
  55. package/lib/commonjs/skia/web/JsiSkColorFilterFactory.js +4 -4
  56. package/lib/commonjs/skia/web/JsiSkColorFilterFactory.js.map +1 -1
  57. package/lib/commonjs/skia/web/JsiSkFont.js +7 -3
  58. package/lib/commonjs/skia/web/JsiSkFont.js.map +1 -1
  59. package/lib/commonjs/skia/web/JsiSkImage.js +4 -2
  60. package/lib/commonjs/skia/web/JsiSkImage.js.map +1 -1
  61. package/lib/commonjs/skia/web/JsiSkImageFactory.js +4 -2
  62. package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
  63. package/lib/commonjs/skia/web/JsiSkImageFilterFactory.js +61 -19
  64. package/lib/commonjs/skia/web/JsiSkImageFilterFactory.js.map +1 -1
  65. package/lib/commonjs/skia/web/JsiSkMatrix.js +1 -1
  66. package/lib/commonjs/skia/web/JsiSkMatrix.js.map +1 -1
  67. package/lib/commonjs/skia/web/JsiSkPaint.js +19 -6
  68. package/lib/commonjs/skia/web/JsiSkPaint.js.map +1 -1
  69. package/lib/commonjs/skia/web/JsiSkPath.js +16 -60
  70. package/lib/commonjs/skia/web/JsiSkPath.js.map +1 -1
  71. package/lib/commonjs/skia/web/JsiSkPathEffectFactory.js +7 -3
  72. package/lib/commonjs/skia/web/JsiSkPathEffectFactory.js.map +1 -1
  73. package/lib/commonjs/skia/web/JsiSkPathFactory.js +1 -1
  74. package/lib/commonjs/skia/web/JsiSkPathFactory.js.map +1 -1
  75. package/lib/commonjs/skia/web/JsiSkPicture.js +5 -1
  76. package/lib/commonjs/skia/web/JsiSkPicture.js.map +1 -1
  77. package/lib/commonjs/skia/web/JsiSkPictureRecorder.js +3 -1
  78. package/lib/commonjs/skia/web/JsiSkPictureRecorder.js.map +1 -1
  79. package/lib/commonjs/skia/web/JsiSkPoint.js +9 -1
  80. package/lib/commonjs/skia/web/JsiSkPoint.js.map +1 -1
  81. package/lib/commonjs/skia/web/JsiSkRRect.js +9 -1
  82. package/lib/commonjs/skia/web/JsiSkRRect.js.map +1 -1
  83. package/lib/commonjs/skia/web/JsiSkRSXform.js.map +1 -1
  84. package/lib/commonjs/skia/web/JsiSkRect.js +3 -3
  85. package/lib/commonjs/skia/web/JsiSkRect.js.map +1 -1
  86. package/lib/commonjs/skia/web/JsiSkRuntimeEffect.js +4 -2
  87. package/lib/commonjs/skia/web/JsiSkRuntimeEffect.js.map +1 -1
  88. package/lib/commonjs/skia/web/JsiSkShaderFactory.js +10 -6
  89. package/lib/commonjs/skia/web/JsiSkShaderFactory.js.map +1 -1
  90. package/lib/commonjs/skia/web/JsiSkSurface.js +3 -1
  91. package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
  92. package/lib/commonjs/skia/web/JsiSkTextBlobFactory.js +8 -4
  93. package/lib/commonjs/skia/web/JsiSkTextBlobFactory.js.map +1 -1
  94. package/lib/commonjs/skia/web/JsiSkTypefaceFactory.js +1 -1
  95. package/lib/commonjs/skia/web/JsiSkTypefaceFactory.js.map +1 -1
  96. package/lib/commonjs/skia/web/JsiSkia.js +12 -6
  97. package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
  98. package/lib/commonjs/values/hooks/useComputedValue.js +6 -2
  99. package/lib/commonjs/values/hooks/useComputedValue.js.map +1 -1
  100. package/lib/commonjs/values/index.js +13 -0
  101. package/lib/commonjs/values/index.js.map +1 -1
  102. package/lib/commonjs/values/selector.js +24 -0
  103. package/lib/commonjs/values/selector.js.map +1 -0
  104. package/lib/commonjs/values/web/RNSkComputedValue.js +8 -0
  105. package/lib/commonjs/values/web/RNSkComputedValue.js.map +1 -1
  106. package/lib/commonjs/values/web/RNSkReadonlyValue.js +4 -0
  107. package/lib/commonjs/values/web/RNSkReadonlyValue.js.map +1 -1
  108. package/lib/module/mock/index.js +2 -1
  109. package/lib/module/mock/index.js.map +1 -1
  110. package/lib/module/renderer/Canvas.js +17 -6
  111. package/lib/module/renderer/Canvas.js.map +1 -1
  112. package/lib/module/renderer/DependencyManager.js +141 -34
  113. package/lib/module/renderer/DependencyManager.js.map +1 -1
  114. package/lib/module/renderer/HostConfig.js +1 -1
  115. package/lib/module/renderer/HostConfig.js.map +1 -1
  116. package/lib/module/renderer/components/Blend.js +21 -5
  117. package/lib/module/renderer/components/Blend.js.map +1 -1
  118. package/lib/module/renderer/components/backdrop/BackdropFilter.js.map +1 -1
  119. package/lib/module/renderer/components/imageFilters/Morphology.js +1 -1
  120. package/lib/module/renderer/components/imageFilters/Morphology.js.map +1 -1
  121. package/lib/module/renderer/components/imageFilters/Shadow.js +1 -1
  122. package/lib/module/renderer/components/imageFilters/Shadow.js.map +1 -1
  123. package/lib/module/renderer/nodes/Declaration.js +3 -4
  124. package/lib/module/renderer/nodes/Declaration.js.map +1 -1
  125. package/lib/module/renderer/nodes/Drawing.js +3 -6
  126. package/lib/module/renderer/nodes/Drawing.js.map +1 -1
  127. package/lib/module/renderer/nodes/Node.js +9 -7
  128. package/lib/module/renderer/nodes/Node.js.map +1 -1
  129. package/lib/module/renderer/processors/Animations/Animations.js +9 -15
  130. package/lib/module/renderer/processors/Animations/Animations.js.map +1 -1
  131. package/lib/module/skia/core/Data.js +10 -20
  132. package/lib/module/skia/core/Data.js.map +1 -1
  133. package/lib/module/skia/core/Font.js +2 -3
  134. package/lib/module/skia/core/Font.js.map +1 -1
  135. package/lib/module/skia/core/Image.js.map +1 -1
  136. package/lib/module/skia/core/SVG.js.map +1 -1
  137. package/lib/module/skia/core/Typeface.js.map +1 -1
  138. package/lib/module/skia/types/Data/Data.js +1 -1
  139. package/lib/module/skia/types/Data/Data.js.map +1 -1
  140. package/lib/module/skia/types/Paint/Paint.js.map +1 -1
  141. package/lib/module/skia/web/Host.js +9 -9
  142. package/lib/module/skia/web/Host.js.map +1 -1
  143. package/lib/module/skia/web/JsiSkCanvas.js +40 -29
  144. package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
  145. package/lib/module/skia/web/JsiSkColorFilterFactory.js +5 -5
  146. package/lib/module/skia/web/JsiSkColorFilterFactory.js.map +1 -1
  147. package/lib/module/skia/web/JsiSkFont.js +6 -4
  148. package/lib/module/skia/web/JsiSkFont.js.map +1 -1
  149. package/lib/module/skia/web/JsiSkImage.js +4 -3
  150. package/lib/module/skia/web/JsiSkImage.js.map +1 -1
  151. package/lib/module/skia/web/JsiSkImageFactory.js +4 -3
  152. package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
  153. package/lib/module/skia/web/JsiSkImageFilterFactory.js +61 -20
  154. package/lib/module/skia/web/JsiSkImageFilterFactory.js.map +1 -1
  155. package/lib/module/skia/web/JsiSkMatrix.js +2 -2
  156. package/lib/module/skia/web/JsiSkMatrix.js.map +1 -1
  157. package/lib/module/skia/web/JsiSkPaint.js +15 -7
  158. package/lib/module/skia/web/JsiSkPaint.js.map +1 -1
  159. package/lib/module/skia/web/JsiSkPath.js +15 -62
  160. package/lib/module/skia/web/JsiSkPath.js.map +1 -1
  161. package/lib/module/skia/web/JsiSkPathEffectFactory.js +6 -4
  162. package/lib/module/skia/web/JsiSkPathEffectFactory.js.map +1 -1
  163. package/lib/module/skia/web/JsiSkPathFactory.js +2 -2
  164. package/lib/module/skia/web/JsiSkPathFactory.js.map +1 -1
  165. package/lib/module/skia/web/JsiSkPicture.js +4 -2
  166. package/lib/module/skia/web/JsiSkPicture.js.map +1 -1
  167. package/lib/module/skia/web/JsiSkPictureRecorder.js +3 -2
  168. package/lib/module/skia/web/JsiSkPictureRecorder.js.map +1 -1
  169. package/lib/module/skia/web/JsiSkPoint.js +10 -2
  170. package/lib/module/skia/web/JsiSkPoint.js.map +1 -1
  171. package/lib/module/skia/web/JsiSkRRect.js +10 -2
  172. package/lib/module/skia/web/JsiSkRRect.js.map +1 -1
  173. package/lib/module/skia/web/JsiSkRSXform.js.map +1 -1
  174. package/lib/module/skia/web/JsiSkRect.js +4 -4
  175. package/lib/module/skia/web/JsiSkRect.js.map +1 -1
  176. package/lib/module/skia/web/JsiSkRuntimeEffect.js +4 -3
  177. package/lib/module/skia/web/JsiSkRuntimeEffect.js.map +1 -1
  178. package/lib/module/skia/web/JsiSkShaderFactory.js +9 -7
  179. package/lib/module/skia/web/JsiSkShaderFactory.js.map +1 -1
  180. package/lib/module/skia/web/JsiSkSurface.js +3 -2
  181. package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
  182. package/lib/module/skia/web/JsiSkTextBlobFactory.js +7 -5
  183. package/lib/module/skia/web/JsiSkTextBlobFactory.js.map +1 -1
  184. package/lib/module/skia/web/JsiSkTypefaceFactory.js +2 -2
  185. package/lib/module/skia/web/JsiSkTypefaceFactory.js.map +1 -1
  186. package/lib/module/skia/web/JsiSkia.js +10 -5
  187. package/lib/module/skia/web/JsiSkia.js.map +1 -1
  188. package/lib/module/values/hooks/useComputedValue.js +7 -3
  189. package/lib/module/values/hooks/useComputedValue.js.map +1 -1
  190. package/lib/module/values/index.js +1 -0
  191. package/lib/module/values/index.js.map +1 -1
  192. package/lib/module/values/selector.js +15 -0
  193. package/lib/module/values/selector.js.map +1 -0
  194. package/lib/module/values/web/RNSkComputedValue.js +8 -0
  195. package/lib/module/values/web/RNSkComputedValue.js.map +1 -1
  196. package/lib/module/values/web/RNSkReadonlyValue.js +4 -0
  197. package/lib/module/values/web/RNSkReadonlyValue.js.map +1 -1
  198. package/lib/typescript/src/renderer/Canvas.d.ts +1 -1
  199. package/lib/typescript/src/renderer/DependencyManager.d.ts +40 -14
  200. package/lib/typescript/src/renderer/nodes/Declaration.d.ts +2 -2
  201. package/lib/typescript/src/renderer/nodes/Drawing.d.ts +2 -2
  202. package/lib/typescript/src/renderer/nodes/Node.d.ts +3 -2
  203. package/lib/typescript/src/renderer/processors/Animations/Animations.d.ts +7 -3
  204. package/lib/typescript/src/skia/core/Data.d.ts +3 -5
  205. package/lib/typescript/src/skia/core/Font.d.ts +2 -2
  206. package/lib/typescript/src/skia/core/Image.d.ts +2 -2
  207. package/lib/typescript/src/skia/core/SVG.d.ts +2 -2
  208. package/lib/typescript/src/skia/core/Typeface.d.ts +2 -2
  209. package/lib/typescript/src/skia/types/Data/Data.d.ts +10 -3
  210. package/lib/typescript/src/skia/types/Paint/Paint.d.ts +5 -0
  211. package/lib/typescript/src/skia/types/Picture/Picture.d.ts +2 -1
  212. package/lib/typescript/src/skia/web/Host.d.ts +6 -8
  213. package/lib/typescript/src/skia/web/JsiSkImageFilterFactory.d.ts +8 -8
  214. package/lib/typescript/src/skia/web/JsiSkPaint.d.ts +1 -0
  215. package/lib/typescript/src/skia/web/JsiSkPoint.d.ts +3 -2
  216. package/lib/typescript/src/skia/web/JsiSkRRect.d.ts +3 -2
  217. package/lib/typescript/src/skia/web/JsiSkRSXform.d.ts +1 -2
  218. package/lib/typescript/src/skia/web/JsiSkRect.d.ts +3 -3
  219. package/lib/typescript/src/skia/web/JsiSkTextBlobFactory.d.ts +2 -1
  220. package/lib/typescript/src/values/index.d.ts +1 -0
  221. package/lib/typescript/src/values/selector.d.ts +14 -0
  222. package/lib/typescript/src/values/types.d.ts +4 -0
  223. package/lib/typescript/src/values/web/RNSkComputedValue.d.ts +1 -0
  224. package/lib/typescript/src/values/web/RNSkReadonlyValue.d.ts +1 -0
  225. package/libs/ios/libskia.xcframework/Info.plist +5 -5
  226. package/libs/ios/libskia.xcframework/ios-arm64_arm64e/libskia.a +0 -0
  227. package/libs/ios/libskia.xcframework/ios-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  228. package/libs/ios/libskshaper.xcframework/ios-arm64_arm64e/libskshaper.a +0 -0
  229. package/libs/ios/libskshaper.xcframework/ios-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  230. package/libs/ios/libsvg.xcframework/ios-arm64_arm64e/libsvg.a +0 -0
  231. package/libs/ios/libsvg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  232. package/package.json +3 -3
  233. package/src/mock/index.ts +2 -1
  234. package/src/renderer/Canvas.tsx +19 -7
  235. package/src/renderer/DependencyManager.tsx +171 -37
  236. package/src/renderer/HostConfig.ts +1 -1
  237. package/src/renderer/components/Blend.tsx +25 -5
  238. package/src/renderer/components/backdrop/BackdropFilter.tsx +1 -1
  239. package/src/renderer/components/imageFilters/Morphology.tsx +2 -2
  240. package/src/renderer/components/imageFilters/Shadow.tsx +2 -2
  241. package/src/renderer/nodes/Declaration.tsx +6 -8
  242. package/src/renderer/nodes/Drawing.tsx +5 -7
  243. package/src/renderer/nodes/Node.ts +11 -9
  244. package/src/renderer/processors/Animations/Animations.ts +23 -14
  245. package/src/skia/core/Data.ts +20 -51
  246. package/src/skia/core/Font.ts +4 -5
  247. package/src/skia/core/Image.ts +2 -2
  248. package/src/skia/core/SVG.ts +2 -2
  249. package/src/skia/core/Typeface.ts +2 -2
  250. package/src/skia/types/Data/Data.ts +11 -1
  251. package/src/skia/types/Paint/Paint.ts +6 -0
  252. package/src/skia/types/Picture/Picture.ts +2 -1
  253. package/src/skia/web/Host.ts +12 -22
  254. package/src/skia/web/JsiSkCanvas.ts +99 -56
  255. package/src/skia/web/JsiSkColorFilterFactory.ts +15 -5
  256. package/src/skia/web/JsiSkFont.ts +11 -4
  257. package/src/skia/web/JsiSkImage.ts +4 -3
  258. package/src/skia/web/JsiSkImageFactory.ts +6 -3
  259. package/src/skia/web/JsiSkImageFilterFactory.ts +124 -52
  260. package/src/skia/web/JsiSkMatrix.ts +4 -2
  261. package/src/skia/web/JsiSkPaint.ts +15 -7
  262. package/src/skia/web/JsiSkPath.ts +30 -56
  263. package/src/skia/web/JsiSkPathEffectFactory.ts +10 -5
  264. package/src/skia/web/JsiSkPathFactory.ts +3 -3
  265. package/src/skia/web/JsiSkPicture.ts +5 -3
  266. package/src/skia/web/JsiSkPictureRecorder.ts +3 -2
  267. package/src/skia/web/JsiSkPoint.ts +12 -2
  268. package/src/skia/web/JsiSkRRect.ts +16 -2
  269. package/src/skia/web/JsiSkRSXform.ts +1 -1
  270. package/src/skia/web/JsiSkRect.ts +4 -7
  271. package/src/skia/web/JsiSkRuntimeEffect.ts +9 -4
  272. package/src/skia/web/JsiSkShaderFactory.ts +24 -15
  273. package/src/skia/web/JsiSkSurface.ts +7 -2
  274. package/src/skia/web/JsiSkTextBlobFactory.ts +14 -8
  275. package/src/skia/web/JsiSkTypefaceFactory.tsx +4 -2
  276. package/src/skia/web/JsiSkia.ts +17 -5
  277. package/src/values/hooks/useComputedValue.ts +6 -3
  278. package/src/values/index.ts +1 -0
  279. package/src/values/selector.ts +24 -0
  280. package/src/values/types.ts +4 -0
  281. package/src/values/web/RNSkComputedValue.ts +6 -0
  282. package/src/values/web/RNSkReadonlyValue.ts +4 -0
@@ -1,59 +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 { 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).filter(isValue);
33
- if (values.length > 0) {
34
- this.subscriptions.set(node, { values, unsubscribe: null });
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
+ );
38
+
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
+ });
35
65
  }
36
66
  }
37
67
 
38
- subscribe() {
39
- if (this.ref.current === null) {
40
- 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;
41
86
  }
42
- this.subscriptions.forEach((subscription) => {
43
- if (subscription.unsubscribe === null) {
44
- subscription.unsubscribe = this.ref.current!.registerValues(
45
- subscription.values
46
- );
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);
47
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
+ );
48
113
  });
49
114
  }
50
115
 
51
- unsubscribe() {
52
- this.subscriptions.forEach(({ unsubscribe }) => {
53
- if (unsubscribe) {
54
- unsubscribe();
55
- }
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));
56
148
  });
149
+
150
+ // 3) Clear the rest of the subscriptions
57
151
  this.subscriptions.clear();
58
152
  }
59
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);
@@ -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
- import type { SkiaValue } from "../../../values";
2
- import { mapKeys } from "../../typeddash";
1
+ import type { SkiaSelector, SkiaValue } from "../../../values";
3
2
 
4
3
  export const isValue = (value: unknown): value is SkiaValue<unknown> => {
5
4
  if (value === undefined || value === null) {
@@ -17,26 +16,36 @@ export const isValue = (value: unknown): value is SkiaValue<unknown> => {
17
16
  return false;
18
17
  };
19
18
 
19
+ export const isSelector = <T, R>(
20
+ value: unknown
21
+ ): value is {
22
+ selector: (v: T) => R;
23
+ value: SkiaValue<T>;
24
+ } => {
25
+ if (value) {
26
+ return (
27
+ typeof value === "object" &&
28
+ "selector" in value &&
29
+ "value" in value &&
30
+ (value as Record<string, unknown>).selector !== undefined &&
31
+ (value as Record<string, unknown>).value !== undefined
32
+ );
33
+ }
34
+ return false;
35
+ };
36
+
20
37
  export const isAnimated = <T>(props: AnimatedProps<T>) => {
21
38
  for (const value of Object.values(props)) {
22
- if (isValue(value)) {
39
+ if (isValue(value) || isSelector(value)) {
23
40
  return true;
24
41
  }
25
42
  }
26
43
  return false;
27
44
  };
28
45
 
29
- export const materialize = <T>(props: AnimatedProps<T>) => {
30
- const result = { ...props };
31
- mapKeys(props).forEach((key) => {
32
- const value = props[key];
33
- if (isValue(value)) {
34
- result[key] = (value as SkiaValue<T[typeof key]>).current;
35
- }
36
- });
37
- return result as T;
38
- };
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ export type AnimatedProp<T, P = any> = T | SkiaValue<T> | SkiaSelector<T, P>;
39
48
 
40
49
  export type AnimatedProps<T> = {
41
- [K in keyof T]: T[K] | SkiaValue<T[K]>;
50
+ [K in keyof T]: AnimatedProp<T[K]>;
42
51
  };
@@ -1,14 +1,14 @@
1
- import type { DependencyList } from "react";
2
- import { useRef, useEffect, useState } from "react";
3
- import { Image, Platform } from "react-native";
1
+ import { useEffect, useState } from "react";
2
+ import { Image } from "react-native";
4
3
 
5
4
  import { Skia } from "../Skia";
6
- import type { SkData, DataSource } from "../types";
5
+ import { isRNModule } from "../types";
6
+ import type { SkData, DataModule, DataSourceParam } from "../types";
7
7
 
8
- const resolveAsset = (source: ReturnType<typeof require>) => {
9
- return Platform.OS === "web"
10
- ? source.default
11
- : Image.resolveAssetSource(source).uri;
8
+ const resolveAsset = (source: DataModule) => {
9
+ return isRNModule(source)
10
+ ? Image.resolveAssetSource(source).uri
11
+ : source.default;
12
12
  };
13
13
 
14
14
  const factoryWrapper = <T>(
@@ -25,19 +25,12 @@ const factoryWrapper = <T>(
25
25
  }
26
26
  };
27
27
 
28
- const loadDataCollection = <T>(
29
- sources: DataSource[],
30
- factory: (data: SkData) => T,
31
- onError?: (err: Error) => void
32
- ): Promise<(T | null)[]> =>
33
- Promise.all(sources.map((source) => loadData(source, factory, onError)));
34
-
35
28
  const loadData = <T>(
36
- source: DataSource,
29
+ source: DataSourceParam,
37
30
  factory: (data: SkData) => T,
38
31
  onError?: (err: Error) => void
39
32
  ): Promise<T | null> => {
40
- if (source === null) {
33
+ if (source === null || source === undefined) {
41
34
  return new Promise((resolve) => resolve(null));
42
35
  } else if (source instanceof Uint8Array) {
43
36
  return new Promise((resolve) =>
@@ -50,51 +43,27 @@ const loadData = <T>(
50
43
  );
51
44
  }
52
45
  };
53
-
54
- type Source = DataSource | null | undefined;
55
-
56
46
  const useLoading = <T>(
57
- source: Source,
58
- loader: () => Promise<T | null>,
59
- deps: DependencyList = []
47
+ source: DataSourceParam,
48
+ loader: () => Promise<T | null>
60
49
  ) => {
61
50
  const [data, setData] = useState<T | null>(null);
62
- const prevSourceRef = useRef<Source>();
63
51
  useEffect(() => {
64
- if (prevSourceRef.current !== source) {
65
- prevSourceRef.current = source;
66
- loader().then(setData);
67
- } else {
68
- setData(null);
69
- }
52
+ loader().then(setData);
70
53
  // eslint-disable-next-line react-hooks/exhaustive-deps
71
- }, deps);
54
+ }, [source]);
72
55
  return data;
73
56
  };
74
57
 
75
- export const useDataCollection = <T>(
76
- sources: DataSource[],
77
- factory: (data: SkData) => T,
78
- onError?: (err: Error) => void,
79
- deps?: DependencyList
80
- ) =>
81
- useLoading(
82
- sources,
83
- () => loadDataCollection(sources, factory, onError),
84
- deps
85
- );
86
-
87
58
  export const useRawData = <T>(
88
- source: DataSource | null | undefined,
59
+ source: DataSourceParam,
89
60
  factory: (data: SkData) => T,
90
- onError?: (err: Error) => void,
91
- deps?: DependencyList
92
- ) => useLoading(source, () => loadData(source, factory, onError), deps);
61
+ onError?: (err: Error) => void
62
+ ) => useLoading(source, () => loadData(source, factory, onError));
93
63
 
94
64
  const identity = (data: SkData) => data;
95
65
 
96
66
  export const useData = (
97
- source: DataSource | null | undefined,
98
- onError?: (err: Error) => void,
99
- deps?: DependencyList
100
- ) => useRawData(source, identity, onError, deps);
67
+ source: DataSourceParam,
68
+ onError?: (err: Error) => void
69
+ ) => useRawData(source, identity, onError);
@@ -2,7 +2,7 @@
2
2
  import { useMemo } from "react";
3
3
 
4
4
  import { Skia } from "../Skia";
5
- import type { DataSource, SkFont } from "../types";
5
+ import type { DataSourceParam } from "../types";
6
6
 
7
7
  import { useTypeface } from "./Typeface";
8
8
 
@@ -10,10 +10,10 @@ import { useTypeface } from "./Typeface";
10
10
  * Returns a Skia Font object
11
11
  * */
12
12
  export const useFont = (
13
- font: DataSource | null | undefined,
13
+ font: DataSourceParam,
14
14
  size?: number,
15
15
  onError?: (err: Error) => void
16
- ): SkFont | null => {
16
+ ) => {
17
17
  const typeface = useTypeface(font, onError);
18
18
  return useMemo(() => {
19
19
  if (typeface && size) {
@@ -23,6 +23,5 @@ export const useFont = (
23
23
  } else {
24
24
  return null;
25
25
  }
26
- // eslint-disable-next-line react-hooks/exhaustive-deps
27
- }, [typeface]);
26
+ }, [size, typeface]);
28
27
  };
@@ -1,5 +1,5 @@
1
1
  import { Skia } from "../Skia";
2
- import type { DataSource } from "../types";
2
+ import type { DataSourceParam } from "../types";
3
3
 
4
4
  import { useRawData } from "./Data";
5
5
 
@@ -9,6 +9,6 @@ const imgFactory = Skia.Image.MakeImageFromEncoded.bind(Skia.Image);
9
9
  * Returns a Skia Image object
10
10
  * */
11
11
  export const useImage = (
12
- source: DataSource | null | undefined,
12
+ source: DataSourceParam,
13
13
  onError?: (err: Error) => void
14
14
  ) => useRawData(source, imgFactory, onError);
@@ -1,11 +1,11 @@
1
1
  import { Skia } from "../Skia";
2
- import type { DataSource } from "../types";
2
+ import type { DataSourceParam } from "../types";
3
3
 
4
4
  import { useRawData } from "./Data";
5
5
 
6
6
  const svgFactory = Skia.SVG.MakeFromData.bind(Skia.SVG);
7
7
 
8
8
  export const useSVG = (
9
- source: DataSource | null | undefined,
9
+ source: DataSourceParam,
10
10
  onError?: (err: Error) => void
11
11
  ) => useRawData(source, svgFactory, onError);