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.
- package/LICENSE +176 -0
- package/README.md +340 -0
- package/dist/DivKit.d.ts +68 -0
- package/dist/DivKit.d.ts.map +1 -0
- package/dist/DivKit.js +400 -0
- package/dist/DivKit.js.map +1 -0
- package/dist/actions/array.d.ts +8 -0
- package/dist/actions/array.d.ts.map +1 -0
- package/dist/actions/array.js +139 -0
- package/dist/actions/array.js.map +1 -0
- package/dist/actions/copyToClipboard.d.ts +22 -0
- package/dist/actions/copyToClipboard.d.ts.map +1 -0
- package/dist/actions/copyToClipboard.js +63 -0
- package/dist/actions/copyToClipboard.js.map +1 -0
- package/dist/actions/dict.d.ts +6 -0
- package/dist/actions/dict.d.ts.map +1 -0
- package/dist/actions/dict.js +58 -0
- package/dist/actions/dict.js.map +1 -0
- package/dist/actions/index.d.ts +11 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +11 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/updateStructure.d.ts +6 -0
- package/dist/actions/updateStructure.d.ts.map +1 -0
- package/dist/actions/updateStructure.js +116 -0
- package/dist/actions/updateStructure.js.map +1 -0
- package/dist/components/DivComponent.d.ts +29 -0
- package/dist/components/DivComponent.d.ts.map +1 -0
- package/dist/components/DivComponent.js +62 -0
- package/dist/components/DivComponent.js.map +1 -0
- package/dist/components/container/DivContainer.d.ts +26 -0
- package/dist/components/container/DivContainer.d.ts.map +1 -0
- package/dist/components/container/DivContainer.js +172 -0
- package/dist/components/container/DivContainer.js.map +1 -0
- package/dist/components/container/index.d.ts +3 -0
- package/dist/components/container/index.d.ts.map +1 -0
- package/dist/components/container/index.js +2 -0
- package/dist/components/container/index.js.map +1 -0
- package/dist/components/image/DivImage.d.ts +29 -0
- package/dist/components/image/DivImage.d.ts.map +1 -0
- package/dist/components/image/DivImage.js +122 -0
- package/dist/components/image/DivImage.js.map +1 -0
- package/dist/components/image/index.d.ts +3 -0
- package/dist/components/image/index.d.ts.map +1 -0
- package/dist/components/image/index.js +2 -0
- package/dist/components/image/index.js.map +1 -0
- package/dist/components/index.d.ts +14 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +11 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/state/DivState.d.ts +26 -0
- package/dist/components/state/DivState.d.ts.map +1 -0
- package/dist/components/state/DivState.js +121 -0
- package/dist/components/state/DivState.js.map +1 -0
- package/dist/components/state/index.d.ts +3 -0
- package/dist/components/state/index.d.ts.map +1 -0
- package/dist/components/state/index.js +2 -0
- package/dist/components/state/index.js.map +1 -0
- package/dist/components/text/DivText.d.ts +28 -0
- package/dist/components/text/DivText.d.ts.map +1 -0
- package/dist/components/text/DivText.js +143 -0
- package/dist/components/text/DivText.js.map +1 -0
- package/dist/components/text/index.d.ts +3 -0
- package/dist/components/text/index.d.ts.map +1 -0
- package/dist/components/text/index.js +2 -0
- package/dist/components/text/index.js.map +1 -0
- package/dist/components/utilities/Outer.d.ts +17 -0
- package/dist/components/utilities/Outer.d.ts.map +1 -0
- package/dist/components/utilities/Outer.js +210 -0
- package/dist/components/utilities/Outer.js.map +1 -0
- package/dist/components/utilities/Unknown.d.ts +11 -0
- package/dist/components/utilities/Unknown.d.ts.map +1 -0
- package/dist/components/utilities/Unknown.js +50 -0
- package/dist/components/utilities/Unknown.js.map +1 -0
- package/dist/components/utilities/index.d.ts +5 -0
- package/dist/components/utilities/index.d.ts.map +1 -0
- package/dist/components/utilities/index.js +3 -0
- package/dist/components/utilities/index.js.map +1 -0
- package/dist/context/ActionContext.d.ts +25 -0
- package/dist/context/ActionContext.d.ts.map +1 -0
- package/dist/context/ActionContext.js +20 -0
- package/dist/context/ActionContext.js.map +1 -0
- package/dist/context/DivKitContext.d.ts +33 -0
- package/dist/context/DivKitContext.d.ts.map +1 -0
- package/dist/context/DivKitContext.js +14 -0
- package/dist/context/DivKitContext.js.map +1 -0
- package/dist/context/EnabledContext.d.ts +31 -0
- package/dist/context/EnabledContext.d.ts.map +1 -0
- package/dist/context/EnabledContext.js +31 -0
- package/dist/context/EnabledContext.js.map +1 -0
- package/dist/context/StateContext.d.ts +57 -0
- package/dist/context/StateContext.d.ts.map +1 -0
- package/dist/context/StateContext.js +20 -0
- package/dist/context/StateContext.js.map +1 -0
- package/dist/context/index.d.ts +9 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +9 -0
- package/dist/context/index.js.map +1 -0
- package/dist/expressions/bigint.d.ts +8 -0
- package/dist/expressions/bigint.d.ts.map +1 -0
- package/dist/expressions/bigint.js +31 -0
- package/dist/expressions/bigint.js.map +1 -0
- package/dist/expressions/const.d.ts +15 -0
- package/dist/expressions/const.d.ts.map +1 -0
- package/dist/expressions/const.js +15 -0
- package/dist/expressions/const.js.map +1 -0
- package/dist/expressions/eval.d.ts +77 -0
- package/dist/expressions/eval.d.ts.map +1 -0
- package/dist/expressions/eval.js +459 -0
- package/dist/expressions/eval.js.map +1 -0
- package/dist/expressions/expressions.d.ts +7 -0
- package/dist/expressions/expressions.d.ts.map +1 -0
- package/dist/expressions/expressions.js +3191 -0
- package/dist/expressions/expressions.js.map +1 -0
- package/dist/expressions/funcs/array.d.ts +2 -0
- package/dist/expressions/funcs/array.d.ts.map +1 -0
- package/dist/expressions/funcs/array.js +381 -0
- package/dist/expressions/funcs/array.js.map +1 -0
- package/dist/expressions/funcs/colors.d.ts +2 -0
- package/dist/expressions/funcs/colors.d.ts.map +1 -0
- package/dist/expressions/funcs/colors.js +75 -0
- package/dist/expressions/funcs/colors.js.map +1 -0
- package/dist/expressions/funcs/customFuncs.d.ts +8 -0
- package/dist/expressions/funcs/customFuncs.d.ts.map +1 -0
- package/dist/expressions/funcs/customFuncs.js +114 -0
- package/dist/expressions/funcs/customFuncs.js.map +1 -0
- package/dist/expressions/funcs/datetime.d.ts +2 -0
- package/dist/expressions/funcs/datetime.d.ts.map +1 -0
- package/dist/expressions/funcs/datetime.js +182 -0
- package/dist/expressions/funcs/datetime.js.map +1 -0
- package/dist/expressions/funcs/dict.d.ts +2 -0
- package/dist/expressions/funcs/dict.d.ts.map +1 -0
- package/dist/expressions/funcs/dict.js +170 -0
- package/dist/expressions/funcs/dict.js.map +1 -0
- package/dist/expressions/funcs/funcs.d.ts +80 -0
- package/dist/expressions/funcs/funcs.d.ts.map +1 -0
- package/dist/expressions/funcs/funcs.js +146 -0
- package/dist/expressions/funcs/funcs.js.map +1 -0
- package/dist/expressions/funcs/index.d.ts +2 -0
- package/dist/expressions/funcs/index.d.ts.map +1 -0
- package/dist/expressions/funcs/index.js +23 -0
- package/dist/expressions/funcs/index.js.map +1 -0
- package/dist/expressions/funcs/interval.d.ts +2 -0
- package/dist/expressions/funcs/interval.d.ts.map +1 -0
- package/dist/expressions/funcs/interval.js +61 -0
- package/dist/expressions/funcs/interval.js.map +1 -0
- package/dist/expressions/funcs/math.d.ts +2 -0
- package/dist/expressions/funcs/math.d.ts.map +1 -0
- package/dist/expressions/funcs/math.js +324 -0
- package/dist/expressions/funcs/math.js.map +1 -0
- package/dist/expressions/funcs/std.d.ts +2 -0
- package/dist/expressions/funcs/std.d.ts.map +1 -0
- package/dist/expressions/funcs/std.js +293 -0
- package/dist/expressions/funcs/std.js.map +1 -0
- package/dist/expressions/funcs/stored.d.ts +4 -0
- package/dist/expressions/funcs/stored.d.ts.map +1 -0
- package/dist/expressions/funcs/stored.js +62 -0
- package/dist/expressions/funcs/stored.js.map +1 -0
- package/dist/expressions/funcs/strings.d.ts +2 -0
- package/dist/expressions/funcs/strings.d.ts.map +1 -0
- package/dist/expressions/funcs/strings.js +158 -0
- package/dist/expressions/funcs/strings.js.map +1 -0
- package/dist/expressions/funcs/trigonometry.d.ts +2 -0
- package/dist/expressions/funcs/trigonometry.d.ts.map +1 -0
- package/dist/expressions/funcs/trigonometry.js +92 -0
- package/dist/expressions/funcs/trigonometry.js.map +1 -0
- package/dist/expressions/json.d.ts +18 -0
- package/dist/expressions/json.d.ts.map +1 -0
- package/dist/expressions/json.js +271 -0
- package/dist/expressions/json.js.map +1 -0
- package/dist/expressions/parserCache.d.ts +4 -0
- package/dist/expressions/parserCache.d.ts.map +1 -0
- package/dist/expressions/parserCache.js +23 -0
- package/dist/expressions/parserCache.js.map +1 -0
- package/dist/expressions/simpleUnescapeString.d.ts +2 -0
- package/dist/expressions/simpleUnescapeString.d.ts.map +1 -0
- package/dist/expressions/simpleUnescapeString.js +61 -0
- package/dist/expressions/simpleUnescapeString.js.map +1 -0
- package/dist/expressions/utils.d.ts +29 -0
- package/dist/expressions/utils.d.ts.map +1 -0
- package/dist/expressions/utils.js +236 -0
- package/dist/expressions/utils.js.map +1 -0
- package/dist/expressions/variable.d.ts +82 -0
- package/dist/expressions/variable.d.ts.map +1 -0
- package/dist/expressions/variable.js +337 -0
- package/dist/expressions/variable.js.map +1 -0
- package/dist/expressions/walk.d.ts +7 -0
- package/dist/expressions/walk.d.ts.map +1 -0
- package/dist/expressions/walk.js +39 -0
- package/dist/expressions/walk.js.map +1 -0
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +11 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useAction.d.ts +102 -0
- package/dist/hooks/useAction.d.ts.map +1 -0
- package/dist/hooks/useAction.js +116 -0
- package/dist/hooks/useAction.js.map +1 -0
- package/dist/hooks/useDerivedFromVars.d.ts +72 -0
- package/dist/hooks/useDerivedFromVars.d.ts.map +1 -0
- package/dist/hooks/useDerivedFromVars.js +100 -0
- package/dist/hooks/useDerivedFromVars.js.map +1 -0
- package/dist/hooks/useVariable.d.ts +86 -0
- package/dist/hooks/useVariable.d.ts.map +1 -0
- package/dist/hooks/useVariable.js +130 -0
- package/dist/hooks/useVariable.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/stores/createObservable.d.ts +38 -0
- package/dist/stores/createObservable.d.ts.map +1 -0
- package/dist/stores/createObservable.js +49 -0
- package/dist/stores/createObservable.js.map +1 -0
- package/dist/utils/applyTemplate.d.ts +8 -0
- package/dist/utils/applyTemplate.d.ts.map +1 -0
- package/dist/utils/applyTemplate.js +94 -0
- package/dist/utils/applyTemplate.js.map +1 -0
- package/dist/utils/correctColor.d.ts +18 -0
- package/dist/utils/correctColor.d.ts.map +1 -0
- package/dist/utils/correctColor.js +79 -0
- package/dist/utils/correctColor.js.map +1 -0
- package/dist/utils/escapeRegExp.d.ts +2 -0
- package/dist/utils/escapeRegExp.d.ts.map +1 -0
- package/dist/utils/escapeRegExp.js +4 -0
- package/dist/utils/escapeRegExp.js.map +1 -0
- package/dist/utils/formatDate.d.ts +6 -0
- package/dist/utils/formatDate.d.ts.map +1 -0
- package/dist/utils/formatDate.js +325 -0
- package/dist/utils/formatDate.js.map +1 -0
- package/dist/utils/padLeft.d.ts +2 -0
- package/dist/utils/padLeft.d.ts.map +1 -0
- package/dist/utils/padLeft.js +7 -0
- package/dist/utils/padLeft.js.map +1 -0
- package/dist/utils/uniq.d.ts +2 -0
- package/dist/utils/uniq.d.ts.map +1 -0
- package/dist/utils/uniq.js +4 -0
- package/dist/utils/uniq.js.map +1 -0
- package/dist/utils/wrapError.d.ts +10 -0
- package/dist/utils/wrapError.d.ts.map +1 -0
- package/dist/utils/wrapError.js +9 -0
- package/dist/utils/wrapError.js.map +1 -0
- package/package.json +58 -0
- package/src/DivKit.tsx +542 -0
- package/src/actions/array.ts +170 -0
- package/src/actions/copyToClipboard.ts +82 -0
- package/src/actions/dict.ts +71 -0
- package/src/actions/index.ts +11 -0
- package/src/actions/updateStructure.ts +134 -0
- package/src/components/DivComponent.tsx +75 -0
- package/src/components/README.md +230 -0
- package/src/components/container/DivContainer.tsx +222 -0
- package/src/components/container/index.ts +2 -0
- package/src/components/image/DivImage.tsx +172 -0
- package/src/components/image/index.ts +2 -0
- package/src/components/index.ts +20 -0
- package/src/components/state/DivState.tsx +146 -0
- package/src/components/state/index.ts +2 -0
- package/src/components/text/DivText.tsx +186 -0
- package/src/components/text/index.ts +2 -0
- package/src/components/utilities/Outer.tsx +239 -0
- package/src/components/utilities/README.md +175 -0
- package/src/components/utilities/Unknown.tsx +60 -0
- package/src/components/utilities/index.ts +4 -0
- package/src/context/ActionContext.tsx +37 -0
- package/src/context/DivKitContext.tsx +54 -0
- package/src/context/EnabledContext.tsx +50 -0
- package/src/context/StateContext.tsx +75 -0
- package/src/context/index.ts +33 -0
- package/src/expressions/ast.d.ts +101 -0
- package/src/expressions/bigint.ts +38 -0
- package/src/expressions/const.ts +16 -0
- package/src/expressions/eval.ts +669 -0
- package/src/expressions/expressions.peggy +235 -0
- package/src/expressions/expressions.ts +2854 -0
- package/src/expressions/funcs/array.ts +412 -0
- package/src/expressions/funcs/colors.ts +100 -0
- package/src/expressions/funcs/customFuncs.ts +139 -0
- package/src/expressions/funcs/datetime.ts +232 -0
- package/src/expressions/funcs/dict.ts +207 -0
- package/src/expressions/funcs/funcs.ts +323 -0
- package/src/expressions/funcs/index.ts +23 -0
- package/src/expressions/funcs/interval.ts +76 -0
- package/src/expressions/funcs/math.ts +395 -0
- package/src/expressions/funcs/std.ts +392 -0
- package/src/expressions/funcs/stored.ts +62 -0
- package/src/expressions/funcs/strings.ts +200 -0
- package/src/expressions/funcs/trigonometry.ts +108 -0
- package/src/expressions/json.ts +367 -0
- package/src/expressions/parserCache.ts +32 -0
- package/src/expressions/simpleUnescapeString.ts +57 -0
- package/src/expressions/utils.ts +271 -0
- package/src/expressions/variable.ts +429 -0
- package/src/expressions/walk.ts +43 -0
- package/src/hooks/README.md +265 -0
- package/src/hooks/index.ts +28 -0
- package/src/hooks/useAction.ts +152 -0
- package/src/hooks/useDerivedFromVars.ts +187 -0
- package/src/hooks/useVariable.ts +157 -0
- package/src/index.ts +97 -0
- package/src/stores/createObservable.ts +64 -0
- package/src/types/alignment.d.ts +13 -0
- package/src/types/background.d.ts +71 -0
- package/src/types/base.d.ts +224 -0
- package/src/types/border.d.ts +46 -0
- package/src/types/componentContext.d.ts +98 -0
- package/src/types/container.d.ts +40 -0
- package/src/types/edgeInserts.d.ts +9 -0
- package/src/types/general.d.ts +3 -0
- package/src/types/image.d.ts +33 -0
- package/src/types/imageScale.d.ts +1 -0
- package/src/types/layoutParams.d.ts +27 -0
- package/src/types/sizes.d.ts +37 -0
- package/src/types/state.d.ts +19 -0
- package/src/types/text.d.ts +126 -0
- package/src/utils/applyTemplate.ts +145 -0
- package/src/utils/correctColor.ts +102 -0
- package/src/utils/escapeRegExp.ts +3 -0
- package/src/utils/formatDate.ts +385 -0
- package/src/utils/padLeft.ts +6 -0
- package/src/utils/uniq.ts +3 -0
- 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
|
+
});
|