react-native-divkit 0.1.0-alpha.1

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 (322) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +340 -0
  3. package/dist/DivKit.d.ts +68 -0
  4. package/dist/DivKit.d.ts.map +1 -0
  5. package/dist/DivKit.js +400 -0
  6. package/dist/DivKit.js.map +1 -0
  7. package/dist/actions/array.d.ts +8 -0
  8. package/dist/actions/array.d.ts.map +1 -0
  9. package/dist/actions/array.js +139 -0
  10. package/dist/actions/array.js.map +1 -0
  11. package/dist/actions/copyToClipboard.d.ts +22 -0
  12. package/dist/actions/copyToClipboard.d.ts.map +1 -0
  13. package/dist/actions/copyToClipboard.js +63 -0
  14. package/dist/actions/copyToClipboard.js.map +1 -0
  15. package/dist/actions/dict.d.ts +6 -0
  16. package/dist/actions/dict.d.ts.map +1 -0
  17. package/dist/actions/dict.js +58 -0
  18. package/dist/actions/dict.js.map +1 -0
  19. package/dist/actions/index.d.ts +11 -0
  20. package/dist/actions/index.d.ts.map +1 -0
  21. package/dist/actions/index.js +11 -0
  22. package/dist/actions/index.js.map +1 -0
  23. package/dist/actions/updateStructure.d.ts +6 -0
  24. package/dist/actions/updateStructure.d.ts.map +1 -0
  25. package/dist/actions/updateStructure.js +116 -0
  26. package/dist/actions/updateStructure.js.map +1 -0
  27. package/dist/components/DivComponent.d.ts +29 -0
  28. package/dist/components/DivComponent.d.ts.map +1 -0
  29. package/dist/components/DivComponent.js +62 -0
  30. package/dist/components/DivComponent.js.map +1 -0
  31. package/dist/components/container/DivContainer.d.ts +26 -0
  32. package/dist/components/container/DivContainer.d.ts.map +1 -0
  33. package/dist/components/container/DivContainer.js +172 -0
  34. package/dist/components/container/DivContainer.js.map +1 -0
  35. package/dist/components/container/index.d.ts +3 -0
  36. package/dist/components/container/index.d.ts.map +1 -0
  37. package/dist/components/container/index.js +2 -0
  38. package/dist/components/container/index.js.map +1 -0
  39. package/dist/components/image/DivImage.d.ts +29 -0
  40. package/dist/components/image/DivImage.d.ts.map +1 -0
  41. package/dist/components/image/DivImage.js +122 -0
  42. package/dist/components/image/DivImage.js.map +1 -0
  43. package/dist/components/image/index.d.ts +3 -0
  44. package/dist/components/image/index.d.ts.map +1 -0
  45. package/dist/components/image/index.js +2 -0
  46. package/dist/components/image/index.js.map +1 -0
  47. package/dist/components/index.d.ts +14 -0
  48. package/dist/components/index.d.ts.map +1 -0
  49. package/dist/components/index.js +11 -0
  50. package/dist/components/index.js.map +1 -0
  51. package/dist/components/state/DivState.d.ts +26 -0
  52. package/dist/components/state/DivState.d.ts.map +1 -0
  53. package/dist/components/state/DivState.js +121 -0
  54. package/dist/components/state/DivState.js.map +1 -0
  55. package/dist/components/state/index.d.ts +3 -0
  56. package/dist/components/state/index.d.ts.map +1 -0
  57. package/dist/components/state/index.js +2 -0
  58. package/dist/components/state/index.js.map +1 -0
  59. package/dist/components/text/DivText.d.ts +28 -0
  60. package/dist/components/text/DivText.d.ts.map +1 -0
  61. package/dist/components/text/DivText.js +143 -0
  62. package/dist/components/text/DivText.js.map +1 -0
  63. package/dist/components/text/index.d.ts +3 -0
  64. package/dist/components/text/index.d.ts.map +1 -0
  65. package/dist/components/text/index.js +2 -0
  66. package/dist/components/text/index.js.map +1 -0
  67. package/dist/components/utilities/Outer.d.ts +17 -0
  68. package/dist/components/utilities/Outer.d.ts.map +1 -0
  69. package/dist/components/utilities/Outer.js +210 -0
  70. package/dist/components/utilities/Outer.js.map +1 -0
  71. package/dist/components/utilities/Unknown.d.ts +11 -0
  72. package/dist/components/utilities/Unknown.d.ts.map +1 -0
  73. package/dist/components/utilities/Unknown.js +50 -0
  74. package/dist/components/utilities/Unknown.js.map +1 -0
  75. package/dist/components/utilities/index.d.ts +5 -0
  76. package/dist/components/utilities/index.d.ts.map +1 -0
  77. package/dist/components/utilities/index.js +3 -0
  78. package/dist/components/utilities/index.js.map +1 -0
  79. package/dist/context/ActionContext.d.ts +25 -0
  80. package/dist/context/ActionContext.d.ts.map +1 -0
  81. package/dist/context/ActionContext.js +20 -0
  82. package/dist/context/ActionContext.js.map +1 -0
  83. package/dist/context/DivKitContext.d.ts +33 -0
  84. package/dist/context/DivKitContext.d.ts.map +1 -0
  85. package/dist/context/DivKitContext.js +14 -0
  86. package/dist/context/DivKitContext.js.map +1 -0
  87. package/dist/context/EnabledContext.d.ts +31 -0
  88. package/dist/context/EnabledContext.d.ts.map +1 -0
  89. package/dist/context/EnabledContext.js +31 -0
  90. package/dist/context/EnabledContext.js.map +1 -0
  91. package/dist/context/StateContext.d.ts +57 -0
  92. package/dist/context/StateContext.d.ts.map +1 -0
  93. package/dist/context/StateContext.js +20 -0
  94. package/dist/context/StateContext.js.map +1 -0
  95. package/dist/context/index.d.ts +9 -0
  96. package/dist/context/index.d.ts.map +1 -0
  97. package/dist/context/index.js +9 -0
  98. package/dist/context/index.js.map +1 -0
  99. package/dist/expressions/bigint.d.ts +8 -0
  100. package/dist/expressions/bigint.d.ts.map +1 -0
  101. package/dist/expressions/bigint.js +31 -0
  102. package/dist/expressions/bigint.js.map +1 -0
  103. package/dist/expressions/const.d.ts +15 -0
  104. package/dist/expressions/const.d.ts.map +1 -0
  105. package/dist/expressions/const.js +15 -0
  106. package/dist/expressions/const.js.map +1 -0
  107. package/dist/expressions/eval.d.ts +77 -0
  108. package/dist/expressions/eval.d.ts.map +1 -0
  109. package/dist/expressions/eval.js +459 -0
  110. package/dist/expressions/eval.js.map +1 -0
  111. package/dist/expressions/expressions.d.ts +7 -0
  112. package/dist/expressions/expressions.d.ts.map +1 -0
  113. package/dist/expressions/expressions.js +3191 -0
  114. package/dist/expressions/expressions.js.map +1 -0
  115. package/dist/expressions/funcs/array.d.ts +2 -0
  116. package/dist/expressions/funcs/array.d.ts.map +1 -0
  117. package/dist/expressions/funcs/array.js +381 -0
  118. package/dist/expressions/funcs/array.js.map +1 -0
  119. package/dist/expressions/funcs/colors.d.ts +2 -0
  120. package/dist/expressions/funcs/colors.d.ts.map +1 -0
  121. package/dist/expressions/funcs/colors.js +75 -0
  122. package/dist/expressions/funcs/colors.js.map +1 -0
  123. package/dist/expressions/funcs/customFuncs.d.ts +8 -0
  124. package/dist/expressions/funcs/customFuncs.d.ts.map +1 -0
  125. package/dist/expressions/funcs/customFuncs.js +114 -0
  126. package/dist/expressions/funcs/customFuncs.js.map +1 -0
  127. package/dist/expressions/funcs/datetime.d.ts +2 -0
  128. package/dist/expressions/funcs/datetime.d.ts.map +1 -0
  129. package/dist/expressions/funcs/datetime.js +182 -0
  130. package/dist/expressions/funcs/datetime.js.map +1 -0
  131. package/dist/expressions/funcs/dict.d.ts +2 -0
  132. package/dist/expressions/funcs/dict.d.ts.map +1 -0
  133. package/dist/expressions/funcs/dict.js +170 -0
  134. package/dist/expressions/funcs/dict.js.map +1 -0
  135. package/dist/expressions/funcs/funcs.d.ts +80 -0
  136. package/dist/expressions/funcs/funcs.d.ts.map +1 -0
  137. package/dist/expressions/funcs/funcs.js +146 -0
  138. package/dist/expressions/funcs/funcs.js.map +1 -0
  139. package/dist/expressions/funcs/index.d.ts +2 -0
  140. package/dist/expressions/funcs/index.d.ts.map +1 -0
  141. package/dist/expressions/funcs/index.js +23 -0
  142. package/dist/expressions/funcs/index.js.map +1 -0
  143. package/dist/expressions/funcs/interval.d.ts +2 -0
  144. package/dist/expressions/funcs/interval.d.ts.map +1 -0
  145. package/dist/expressions/funcs/interval.js +61 -0
  146. package/dist/expressions/funcs/interval.js.map +1 -0
  147. package/dist/expressions/funcs/math.d.ts +2 -0
  148. package/dist/expressions/funcs/math.d.ts.map +1 -0
  149. package/dist/expressions/funcs/math.js +324 -0
  150. package/dist/expressions/funcs/math.js.map +1 -0
  151. package/dist/expressions/funcs/std.d.ts +2 -0
  152. package/dist/expressions/funcs/std.d.ts.map +1 -0
  153. package/dist/expressions/funcs/std.js +293 -0
  154. package/dist/expressions/funcs/std.js.map +1 -0
  155. package/dist/expressions/funcs/stored.d.ts +4 -0
  156. package/dist/expressions/funcs/stored.d.ts.map +1 -0
  157. package/dist/expressions/funcs/stored.js +62 -0
  158. package/dist/expressions/funcs/stored.js.map +1 -0
  159. package/dist/expressions/funcs/strings.d.ts +2 -0
  160. package/dist/expressions/funcs/strings.d.ts.map +1 -0
  161. package/dist/expressions/funcs/strings.js +158 -0
  162. package/dist/expressions/funcs/strings.js.map +1 -0
  163. package/dist/expressions/funcs/trigonometry.d.ts +2 -0
  164. package/dist/expressions/funcs/trigonometry.d.ts.map +1 -0
  165. package/dist/expressions/funcs/trigonometry.js +92 -0
  166. package/dist/expressions/funcs/trigonometry.js.map +1 -0
  167. package/dist/expressions/json.d.ts +18 -0
  168. package/dist/expressions/json.d.ts.map +1 -0
  169. package/dist/expressions/json.js +271 -0
  170. package/dist/expressions/json.js.map +1 -0
  171. package/dist/expressions/parserCache.d.ts +4 -0
  172. package/dist/expressions/parserCache.d.ts.map +1 -0
  173. package/dist/expressions/parserCache.js +23 -0
  174. package/dist/expressions/parserCache.js.map +1 -0
  175. package/dist/expressions/simpleUnescapeString.d.ts +2 -0
  176. package/dist/expressions/simpleUnescapeString.d.ts.map +1 -0
  177. package/dist/expressions/simpleUnescapeString.js +61 -0
  178. package/dist/expressions/simpleUnescapeString.js.map +1 -0
  179. package/dist/expressions/utils.d.ts +29 -0
  180. package/dist/expressions/utils.d.ts.map +1 -0
  181. package/dist/expressions/utils.js +236 -0
  182. package/dist/expressions/utils.js.map +1 -0
  183. package/dist/expressions/variable.d.ts +82 -0
  184. package/dist/expressions/variable.d.ts.map +1 -0
  185. package/dist/expressions/variable.js +337 -0
  186. package/dist/expressions/variable.js.map +1 -0
  187. package/dist/expressions/walk.d.ts +7 -0
  188. package/dist/expressions/walk.d.ts.map +1 -0
  189. package/dist/expressions/walk.js +39 -0
  190. package/dist/expressions/walk.js.map +1 -0
  191. package/dist/hooks/index.d.ts +8 -0
  192. package/dist/hooks/index.d.ts.map +1 -0
  193. package/dist/hooks/index.js +11 -0
  194. package/dist/hooks/index.js.map +1 -0
  195. package/dist/hooks/useAction.d.ts +102 -0
  196. package/dist/hooks/useAction.d.ts.map +1 -0
  197. package/dist/hooks/useAction.js +116 -0
  198. package/dist/hooks/useAction.js.map +1 -0
  199. package/dist/hooks/useDerivedFromVars.d.ts +72 -0
  200. package/dist/hooks/useDerivedFromVars.d.ts.map +1 -0
  201. package/dist/hooks/useDerivedFromVars.js +100 -0
  202. package/dist/hooks/useDerivedFromVars.js.map +1 -0
  203. package/dist/hooks/useVariable.d.ts +86 -0
  204. package/dist/hooks/useVariable.d.ts.map +1 -0
  205. package/dist/hooks/useVariable.js +130 -0
  206. package/dist/hooks/useVariable.js.map +1 -0
  207. package/dist/index.d.ts +30 -0
  208. package/dist/index.d.ts.map +1 -0
  209. package/dist/index.js +28 -0
  210. package/dist/index.js.map +1 -0
  211. package/dist/stores/createObservable.d.ts +38 -0
  212. package/dist/stores/createObservable.d.ts.map +1 -0
  213. package/dist/stores/createObservable.js +49 -0
  214. package/dist/stores/createObservable.js.map +1 -0
  215. package/dist/utils/applyTemplate.d.ts +8 -0
  216. package/dist/utils/applyTemplate.d.ts.map +1 -0
  217. package/dist/utils/applyTemplate.js +94 -0
  218. package/dist/utils/applyTemplate.js.map +1 -0
  219. package/dist/utils/correctColor.d.ts +18 -0
  220. package/dist/utils/correctColor.d.ts.map +1 -0
  221. package/dist/utils/correctColor.js +79 -0
  222. package/dist/utils/correctColor.js.map +1 -0
  223. package/dist/utils/escapeRegExp.d.ts +2 -0
  224. package/dist/utils/escapeRegExp.d.ts.map +1 -0
  225. package/dist/utils/escapeRegExp.js +4 -0
  226. package/dist/utils/escapeRegExp.js.map +1 -0
  227. package/dist/utils/formatDate.d.ts +6 -0
  228. package/dist/utils/formatDate.d.ts.map +1 -0
  229. package/dist/utils/formatDate.js +325 -0
  230. package/dist/utils/formatDate.js.map +1 -0
  231. package/dist/utils/padLeft.d.ts +2 -0
  232. package/dist/utils/padLeft.d.ts.map +1 -0
  233. package/dist/utils/padLeft.js +7 -0
  234. package/dist/utils/padLeft.js.map +1 -0
  235. package/dist/utils/uniq.d.ts +2 -0
  236. package/dist/utils/uniq.d.ts.map +1 -0
  237. package/dist/utils/uniq.js +4 -0
  238. package/dist/utils/uniq.js.map +1 -0
  239. package/dist/utils/wrapError.d.ts +10 -0
  240. package/dist/utils/wrapError.d.ts.map +1 -0
  241. package/dist/utils/wrapError.js +9 -0
  242. package/dist/utils/wrapError.js.map +1 -0
  243. package/package.json +58 -0
  244. package/src/DivKit.tsx +542 -0
  245. package/src/actions/array.ts +170 -0
  246. package/src/actions/copyToClipboard.ts +82 -0
  247. package/src/actions/dict.ts +71 -0
  248. package/src/actions/index.ts +11 -0
  249. package/src/actions/updateStructure.ts +134 -0
  250. package/src/components/DivComponent.tsx +75 -0
  251. package/src/components/README.md +230 -0
  252. package/src/components/container/DivContainer.tsx +222 -0
  253. package/src/components/container/index.ts +2 -0
  254. package/src/components/image/DivImage.tsx +172 -0
  255. package/src/components/image/index.ts +2 -0
  256. package/src/components/index.ts +20 -0
  257. package/src/components/state/DivState.tsx +146 -0
  258. package/src/components/state/index.ts +2 -0
  259. package/src/components/text/DivText.tsx +186 -0
  260. package/src/components/text/index.ts +2 -0
  261. package/src/components/utilities/Outer.tsx +239 -0
  262. package/src/components/utilities/README.md +175 -0
  263. package/src/components/utilities/Unknown.tsx +60 -0
  264. package/src/components/utilities/index.ts +4 -0
  265. package/src/context/ActionContext.tsx +37 -0
  266. package/src/context/DivKitContext.tsx +54 -0
  267. package/src/context/EnabledContext.tsx +50 -0
  268. package/src/context/StateContext.tsx +75 -0
  269. package/src/context/index.ts +33 -0
  270. package/src/expressions/ast.d.ts +101 -0
  271. package/src/expressions/bigint.ts +38 -0
  272. package/src/expressions/const.ts +16 -0
  273. package/src/expressions/eval.ts +669 -0
  274. package/src/expressions/expressions.peggy +235 -0
  275. package/src/expressions/expressions.ts +2854 -0
  276. package/src/expressions/funcs/array.ts +412 -0
  277. package/src/expressions/funcs/colors.ts +100 -0
  278. package/src/expressions/funcs/customFuncs.ts +139 -0
  279. package/src/expressions/funcs/datetime.ts +232 -0
  280. package/src/expressions/funcs/dict.ts +207 -0
  281. package/src/expressions/funcs/funcs.ts +323 -0
  282. package/src/expressions/funcs/index.ts +23 -0
  283. package/src/expressions/funcs/interval.ts +76 -0
  284. package/src/expressions/funcs/math.ts +395 -0
  285. package/src/expressions/funcs/std.ts +392 -0
  286. package/src/expressions/funcs/stored.ts +62 -0
  287. package/src/expressions/funcs/strings.ts +200 -0
  288. package/src/expressions/funcs/trigonometry.ts +108 -0
  289. package/src/expressions/json.ts +367 -0
  290. package/src/expressions/parserCache.ts +32 -0
  291. package/src/expressions/simpleUnescapeString.ts +57 -0
  292. package/src/expressions/utils.ts +271 -0
  293. package/src/expressions/variable.ts +429 -0
  294. package/src/expressions/walk.ts +43 -0
  295. package/src/hooks/README.md +265 -0
  296. package/src/hooks/index.ts +28 -0
  297. package/src/hooks/useAction.ts +152 -0
  298. package/src/hooks/useDerivedFromVars.ts +187 -0
  299. package/src/hooks/useVariable.ts +157 -0
  300. package/src/index.ts +97 -0
  301. package/src/stores/createObservable.ts +64 -0
  302. package/src/types/alignment.d.ts +13 -0
  303. package/src/types/background.d.ts +71 -0
  304. package/src/types/base.d.ts +224 -0
  305. package/src/types/border.d.ts +46 -0
  306. package/src/types/componentContext.d.ts +98 -0
  307. package/src/types/container.d.ts +40 -0
  308. package/src/types/edgeInserts.d.ts +9 -0
  309. package/src/types/general.d.ts +3 -0
  310. package/src/types/image.d.ts +33 -0
  311. package/src/types/imageScale.d.ts +1 -0
  312. package/src/types/layoutParams.d.ts +27 -0
  313. package/src/types/sizes.d.ts +37 -0
  314. package/src/types/state.d.ts +19 -0
  315. package/src/types/text.d.ts +126 -0
  316. package/src/utils/applyTemplate.ts +145 -0
  317. package/src/utils/correctColor.ts +102 -0
  318. package/src/utils/escapeRegExp.ts +3 -0
  319. package/src/utils/formatDate.ts +385 -0
  320. package/src/utils/padLeft.ts +6 -0
  321. package/src/utils/uniq.ts +3 -0
  322. package/src/utils/wrapError.ts +21 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapError.js","sourceRoot":"","sources":["../../src/utils/wrapError.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,SAAS,CAAC,KAAY,EAAE,SAGpC,EAAE;IACF,MAAM,OAAO,GAAG,KAAqB,CAAC;IAEtC,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC;IAExC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACpB,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAC3C,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "react-native-divkit",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "DivKit renderer for React Native - Server-driven UI framework",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "src",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "scripts": {
14
+ "build": "npm run build:peggy && tsc",
15
+ "build:peggy": "peggy src/expressions/expressions.peggy --allowed-start-rules start,JsonStringContents --format es -o src/expressions/expressions.ts && printf '%s\n%s\n' '// @ts-nocheck' \"$(cat src/expressions/expressions.ts)\" > src/expressions/expressions.ts",
16
+ "test": "jest",
17
+ "lint": "eslint src --ext .ts,.tsx",
18
+ "typecheck": "tsc --noEmit"
19
+ },
20
+ "keywords": [
21
+ "divkit",
22
+ "react-native",
23
+ "server-driven-ui",
24
+ "dynamic-ui",
25
+ "mobile"
26
+ ],
27
+ "author": "Ruslan Pulatov",
28
+ "license": "Apache-2.0",
29
+ "peerDependencies": {
30
+ "react": ">=18.0.0",
31
+ "react-native": ">=0.72.0"
32
+ },
33
+ "dependencies": {
34
+ "peggy": "^3.0.2"
35
+ },
36
+ "optionalDependencies": {
37
+ "react-native-fast-image": "^8.6.3",
38
+ "react-native-linear-gradient": "^2.8.3",
39
+ "@react-native-clipboard/clipboard": "^1.13.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/react": "^18.2.0",
43
+ "@types/react-native": "^0.72.0",
44
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
45
+ "@typescript-eslint/parser": "^5.59.0",
46
+ "eslint": "^8.47.0",
47
+ "typescript": "^5.7.0",
48
+ "jest": "^29.0.0",
49
+ "ts-jest": "^29.0.0",
50
+ "@testing-library/react-native": "^12.0.0",
51
+ "@types/jest": "^29.0.0",
52
+ "react-test-renderer": "^18.2.0"
53
+ },
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "https://github.com/rpulatov/react-native-divkit.git"
57
+ }
58
+ }
package/src/DivKit.tsx ADDED
@@ -0,0 +1,542 @@
1
+ /**
2
+ * DivKit - Main entry point component for React Native
3
+ *
4
+ * Based on Root.svelte from Web implementation
5
+ * Provides context setup, variable management, and component rendering
6
+ *
7
+ * MVP Scope:
8
+ * - 4 basic components (Text, Container, Image, State)
9
+ * - Variable system with reactive updates
10
+ * - Action execution
11
+ * - Template resolution
12
+ *
13
+ * Deferred for post-MVP:
14
+ * - Timers
15
+ * - Variable triggers
16
+ * - Complex animations
17
+ * - Custom components
18
+ * - Extensions
19
+ */
20
+
21
+ import React, { useMemo, useCallback, useRef } from 'react';
22
+ import { View, StyleSheet, type ViewStyle } from 'react-native';
23
+ import type { Action, DivJson, DivVariable, Direction } from '../typings/common';
24
+ import type { DivBaseData } from './types/base';
25
+ import type { ComponentContext } from './types/componentContext';
26
+ import type { MaybeMissing } from './expressions/json';
27
+ import { DivKitContext, type DivKitContextValue } from './context/DivKitContext';
28
+ import { ActionContext, type ActionContextValue } from './context/ActionContext';
29
+ import { StateContext, type StateContextValue, type StateSetter } from './context/StateContext';
30
+ import { DivComponent } from './components/DivComponent';
31
+ import { createVariable, Variable, type VariableType } from './expressions/variable';
32
+ import { applyTemplatesRecursively } from './utils/applyTemplate';
33
+ import { wrapError, type WrappedError } from './utils/wrapError';
34
+ import { arrayInsert, arrayRemove, arraySet } from './actions/array';
35
+ import { dictSetValue } from './actions/dict';
36
+ import { copyToClipboard } from './actions/copyToClipboard';
37
+ import { updateStructure } from './actions/updateStructure';
38
+ import { evalExpression } from './expressions/eval';
39
+
40
+ /**
41
+ * Callback for logging statistics
42
+ */
43
+ export type StatCallback = (stat: {
44
+ type: string;
45
+ action: Action;
46
+ }) => void;
47
+
48
+ /**
49
+ * Callback for custom actions (actions with URLs)
50
+ */
51
+ export type CustomActionCallback = (action: Action & { url: string }) => void;
52
+
53
+ /**
54
+ * Callback for errors
55
+ */
56
+ export type ErrorCallback = (error: WrappedError) => void;
57
+
58
+ /**
59
+ * Props for DivKit component
60
+ */
61
+ export interface DivKitProps {
62
+ /** DivKit JSON data */
63
+ data: Partial<DivJson>;
64
+
65
+ /** Callback for statistics/logging */
66
+ onStat?: StatCallback;
67
+
68
+ /** Callback for custom actions */
69
+ onCustomAction?: CustomActionCallback;
70
+
71
+ /** Callback for errors */
72
+ onError?: ErrorCallback;
73
+
74
+ /** Text direction (default: 'ltr') */
75
+ direction?: Direction;
76
+
77
+ /** Platform type (default: 'touch' for mobile) */
78
+ platform?: 'desktop' | 'touch';
79
+
80
+ /** Custom style for the root container */
81
+ style?: ViewStyle;
82
+
83
+ /** Component ID (for debugging) */
84
+ id?: string;
85
+ }
86
+
87
+ /**
88
+ * DivKit - Main component
89
+ *
90
+ * Renders DivKit JSON as React Native components
91
+ */
92
+ export function DivKit({
93
+ data,
94
+ onStat,
95
+ onCustomAction,
96
+ onError,
97
+ direction = 'ltr',
98
+ platform = 'touch',
99
+ style,
100
+ id = 'root'
101
+ }: DivKitProps) {
102
+ const componentIdCounter = useRef(0);
103
+ const componentsMap = useRef<Map<string, ComponentContext>>(new Map());
104
+ const statesMap = useRef<Map<string, StateSetter>>(new Map());
105
+
106
+ // Error logging
107
+ const logError = useCallback((error: WrappedError) => {
108
+ if (onError) {
109
+ onError(error);
110
+ } else {
111
+ console.error('[DivKit Error]', error);
112
+ }
113
+ }, [onError]);
114
+
115
+ // Parse JSON and apply templates
116
+ const { rootDiv, initialVariables } = useMemo(() => {
117
+ const card = data.card;
118
+ if (!card || !card.states || card.states.length === 0) {
119
+ logError(wrapError(new Error('Invalid DivKit JSON: missing card or states')));
120
+ return {
121
+ rootDiv: null,
122
+ initialVariables: []
123
+ };
124
+ }
125
+
126
+ const state = card.states[0];
127
+ const divData = state.div;
128
+ const templatesData = data.templates || {};
129
+
130
+ // Apply template if needed
131
+ let resolvedDiv = divData;
132
+ if (divData && typeof divData === 'object' && 'type' in divData) {
133
+ try {
134
+ // Use recursive template application to handle nested templates
135
+ resolvedDiv = applyTemplatesRecursively(
136
+ divData,
137
+ templatesData,
138
+ logError
139
+ );
140
+ } catch (err) {
141
+ logError(wrapError(err as Error, {
142
+ additional: { phase: 'template_resolution' }
143
+ }));
144
+ }
145
+ }
146
+
147
+ return {
148
+ rootDiv: resolvedDiv as DivBaseData | null,
149
+ initialVariables: card.variables || []
150
+ };
151
+ }, [data, logError]);
152
+
153
+ // Initialize variables
154
+ const variables = useMemo(() => {
155
+ const map = new Map<string, Variable>();
156
+
157
+ initialVariables.forEach((varData: DivVariable) => {
158
+ try {
159
+ // Skip property variables for MVP (complex feature)
160
+ if (varData.type === 'property') {
161
+ return;
162
+ }
163
+
164
+ const variable = createVariable(
165
+ varData.name,
166
+ varData.type as VariableType,
167
+ varData.value
168
+ );
169
+ map.set(varData.name, variable);
170
+ } catch (err) {
171
+ logError(wrapError(err as Error, {
172
+ additional: {
173
+ variable: varData.name,
174
+ type: varData.type
175
+ }
176
+ }));
177
+ }
178
+ });
179
+
180
+ return map;
181
+ }, [initialVariables, logError]);
182
+
183
+ // Generate unique component IDs
184
+ const genId = useCallback((key: string): string => {
185
+ return `${key}_${componentIdCounter.current++}`;
186
+ }, []);
187
+
188
+ // Variable management
189
+ const getVariable = useCallback((name: string): Variable | undefined => {
190
+ return variables.get(name);
191
+ }, [variables]);
192
+
193
+ const setVariable = useCallback((name: string, value: unknown): void => {
194
+ const variable = variables.get(name);
195
+ if (!variable) {
196
+ logError(wrapError(new Error('Variable not found'), {
197
+ additional: { variable: name }
198
+ }));
199
+ return;
200
+ }
201
+
202
+ try {
203
+ variable.setValue(value);
204
+ } catch (err) {
205
+ logError(wrapError(err as Error, {
206
+ additional: {
207
+ variable: name,
208
+ value
209
+ }
210
+ }));
211
+ }
212
+ }, [variables, logError]);
213
+
214
+ // Action execution
215
+ const execAnyActions = useCallback(async (
216
+ actions: MaybeMissing<Action[]> | undefined,
217
+ opts?: {
218
+ componentContext?: ComponentContext;
219
+ processUrls?: boolean;
220
+ }
221
+ ): Promise<void> => {
222
+ if (!actions || !Array.isArray(actions)) {
223
+ return;
224
+ }
225
+
226
+ const processUrls = opts?.processUrls ?? true;
227
+ const componentContext = opts?.componentContext;
228
+
229
+ for (const action of actions) {
230
+ if (!action) continue;
231
+
232
+ // Log statistics
233
+ if (action.log_id && onStat) {
234
+ onStat({
235
+ type: 'action',
236
+ action: action as Action
237
+ });
238
+ }
239
+
240
+ // Handle typed actions
241
+ if (action.typed) {
242
+ const typed = action.typed;
243
+
244
+ try {
245
+ switch (typed.type) {
246
+ case 'set_variable':
247
+ if (typed.variable_name && typed.value) {
248
+ const typedValue = typed.value;
249
+ let value: unknown;
250
+
251
+ // Convert typed value to raw value
252
+ if (typeof typedValue === 'object' && typedValue !== null && 'value' in typedValue) {
253
+ value = typedValue.value;
254
+ } else {
255
+ value = typedValue;
256
+ }
257
+
258
+ setVariable(typed.variable_name, value);
259
+ }
260
+ break;
261
+
262
+ case 'set_state': {
263
+ const setStateAction = typed as any;
264
+ if (setStateAction.state_id && setStateAction.temporary_state_id) {
265
+ const setter = statesMap.current.get(setStateAction.state_id);
266
+ if (setter) {
267
+ await setter(String(setStateAction.temporary_state_id));
268
+ }
269
+ }
270
+ break;
271
+ }
272
+
273
+ case 'array_insert_value':
274
+ arrayInsert(componentContext, variables, logError, typed as any);
275
+ break;
276
+
277
+ case 'array_remove_value':
278
+ arrayRemove(componentContext, variables, logError, typed as any);
279
+ break;
280
+
281
+ case 'array_set_value':
282
+ arraySet(componentContext, variables, logError, typed as any);
283
+ break;
284
+
285
+ case 'dict_set_value':
286
+ dictSetValue(componentContext, variables, logError, typed as any);
287
+ break;
288
+
289
+ case 'update_structure':
290
+ updateStructure(componentContext, variables, logError, typed as any);
291
+ break;
292
+
293
+ case 'copy_to_clipboard':
294
+ copyToClipboard(logError, typed as any);
295
+ break;
296
+
297
+ // MVP: Other action types deferred (timer, animator, etc.)
298
+ default:
299
+ break;
300
+ }
301
+ } catch (err) {
302
+ logError(wrapError(err as Error, {
303
+ additional: {
304
+ action: typed.type
305
+ }
306
+ }));
307
+ }
308
+ }
309
+
310
+ // Handle URL actions
311
+ if (processUrls && action.url && onCustomAction) {
312
+ onCustomAction(action as Action & { url: string });
313
+ }
314
+ }
315
+ }, [variables, logError, onStat, onCustomAction, setVariable]);
316
+
317
+ // Component registration
318
+ const registerComponent = useCallback((_componentId: string, context: ComponentContext): void => {
319
+ componentsMap.current.set(context.id, context);
320
+ }, []);
321
+
322
+ const unregisterComponent = useCallback((_componentId: string): void => {
323
+ // Component cleanup
324
+ }, []);
325
+
326
+ // State Context implementation
327
+ const stateContextValue = useMemo<StateContextValue>(() => ({
328
+ registerState: (componentId: string, setState: StateSetter): (() => void) => {
329
+ statesMap.current.set(componentId, setState);
330
+ return () => {
331
+ statesMap.current.delete(componentId);
332
+ };
333
+ },
334
+
335
+ switchState: async (stateId: string): Promise<void> => {
336
+ const setter = statesMap.current.get(stateId);
337
+ if (setter) {
338
+ await setter(stateId);
339
+ }
340
+ },
341
+
342
+ getStateSetter: (componentId: string): StateSetter | undefined => {
343
+ return statesMap.current.get(componentId);
344
+ },
345
+
346
+ registerChild: (_componentId: string): void => {
347
+ // MVP: Simplified implementation
348
+ // Full transition tracking deferred
349
+ },
350
+
351
+ unregisterChild: (_componentId: string): void => {
352
+ // MVP: Simplified implementation
353
+ },
354
+
355
+ hasTransitionChange: (): boolean => {
356
+ // MVP: Always false (transitions deferred)
357
+ return false;
358
+ }
359
+ }), []);
360
+
361
+ // Action Context implementation
362
+ const actionContextValue = useMemo<ActionContextValue>(() => ({
363
+ hasAction: (): boolean => {
364
+ // MVP: Simplified - always return false
365
+ // Full action tracking deferred
366
+ return false;
367
+ }
368
+ }), []);
369
+
370
+ // DivKit Context implementation
371
+ const divKitContextValue = useMemo<DivKitContextValue>(() => ({
372
+ logStat: (type: string, action: MaybeMissing<Action>) => {
373
+ if (onStat && action && action.log_id) {
374
+ onStat({ type, action: action as Action });
375
+ }
376
+ },
377
+
378
+ execCustomAction: (action: Action & { url: string }) => {
379
+ if (onCustomAction) {
380
+ onCustomAction(action);
381
+ }
382
+ },
383
+
384
+ direction,
385
+ platform,
386
+
387
+ variables,
388
+ getVariable,
389
+ setVariable,
390
+
391
+ registerComponent,
392
+ unregisterComponent,
393
+
394
+ execAnyActions,
395
+
396
+ genId
397
+ }), [
398
+ onStat,
399
+ onCustomAction,
400
+ direction,
401
+ platform,
402
+ variables,
403
+ getVariable,
404
+ setVariable,
405
+ registerComponent,
406
+ unregisterComponent,
407
+ execAnyActions,
408
+ genId
409
+ ]);
410
+
411
+ // Create root component context
412
+ const rootComponentContext = useMemo<ComponentContext<DivBaseData> | null>(() => {
413
+ if (!rootDiv) {
414
+ return null;
415
+ }
416
+
417
+ const context: ComponentContext<DivBaseData> = {
418
+ path: [],
419
+ json: rootDiv as MaybeMissing<DivBaseData>,
420
+ origJson: rootDiv as MaybeMissing<DivBaseData>,
421
+ templateContext: {},
422
+ variables,
423
+ id: genId(id),
424
+
425
+ logError,
426
+
427
+ execAnyActions,
428
+
429
+ // MVP: Simplified implementations
430
+ getDerivedFromVars: <T,>(jsonProp: T): any => {
431
+ // This is a placeholder for Svelte's readable store
432
+ // In React Native, we use hooks instead (useDerivedFromVars)
433
+ return jsonProp;
434
+ },
435
+
436
+ getJsonWithVars: <T,>(jsonProp: T): MaybeMissing<T> => {
437
+ // Simplified implementation for MVP
438
+ return jsonProp as MaybeMissing<T>;
439
+ },
440
+
441
+ evalExpression: (store: any, expr: any, opts?: any) => {
442
+ const allVars = variables;
443
+ return evalExpression(allVars, undefined, store, expr, opts);
444
+ },
445
+
446
+ produceChildContext: (
447
+ div: MaybeMissing<DivBaseData>,
448
+ opts?: any
449
+ ): ComponentContext => {
450
+ const childPath = opts?.path !== undefined
451
+ ? [...context.path, String(opts.path)]
452
+ : context.path;
453
+
454
+ const childContext: ComponentContext = {
455
+ ...context,
456
+ path: childPath,
457
+ parent: context,
458
+ json: div,
459
+ origJson: opts?.origJson || div,
460
+ id: opts?.id || genId('component'),
461
+ variables: opts?.variables || variables,
462
+ isRootState: opts?.isRootState,
463
+ isTooltipRoot: opts?.isTooltipRoot,
464
+ key: opts?.key
465
+ };
466
+
467
+ return childContext;
468
+ },
469
+
470
+ dup: (fakeReason: number): ComponentContext => {
471
+ return {
472
+ ...context,
473
+ fakeElement: fakeReason
474
+ };
475
+ },
476
+
477
+ getVariable: (varName: string): Variable | undefined => {
478
+ return variables.get(varName);
479
+ },
480
+
481
+ getAnimator: (): undefined => {
482
+ // MVP: Animators deferred
483
+ return undefined;
484
+ },
485
+
486
+ registerState: (stateId: string, setState: any): (() => void) => {
487
+ // Convert ComponentContext StateSetter to StateContext StateSetter
488
+ const wrappedSetState = async (id: string) => {
489
+ await setState(id);
490
+ return undefined;
491
+ };
492
+ return stateContextValue.registerState(stateId, wrappedSetState);
493
+ },
494
+
495
+ registerPager: (): any => {
496
+ // MVP: Pagers deferred
497
+ return {
498
+ update: () => {},
499
+ destroy: () => {}
500
+ };
501
+ },
502
+
503
+ listenPager: (): (() => void) => {
504
+ // MVP: Pagers deferred
505
+ return () => {};
506
+ },
507
+
508
+ destroy: (): void => {
509
+ // Cleanup if needed
510
+ }
511
+ };
512
+
513
+ return context;
514
+ }, [rootDiv, variables, logError, execAnyActions, genId, id, stateContextValue]);
515
+
516
+ // Render
517
+ if (!rootDiv || !rootComponentContext) {
518
+ return (
519
+ <View style={[styles.container, style]}>
520
+ {/* Empty state - could render error UI here */}
521
+ </View>
522
+ );
523
+ }
524
+
525
+ return (
526
+ <DivKitContext.Provider value={divKitContextValue}>
527
+ <ActionContext.Provider value={actionContextValue}>
528
+ <StateContext.Provider value={stateContextValue}>
529
+ <View style={[styles.container, style]}>
530
+ <DivComponent componentContext={rootComponentContext} />
531
+ </View>
532
+ </StateContext.Provider>
533
+ </ActionContext.Provider>
534
+ </DivKitContext.Provider>
535
+ );
536
+ }
537
+
538
+ const styles = StyleSheet.create({
539
+ container: {
540
+ flex: 1
541
+ }
542
+ });