react-native-divkit 0.1.0-alpha.1 → 0.1.0-alpha.3
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/README.md +200 -201
- package/dist/DivKit.d.ts.map +1 -1
- package/dist/DivKit.js +24 -7
- package/dist/DivKit.js.map +1 -1
- package/dist/actions/array.d.ts.map +1 -1
- package/dist/actions/array.js +1 -1
- package/dist/actions/array.js.map +1 -1
- package/dist/actions/copyToClipboard.d.ts.map +1 -1
- package/dist/actions/copyToClipboard.js +2 -1
- package/dist/actions/copyToClipboard.js.map +1 -1
- package/dist/actions/dict.d.ts.map +1 -1
- package/dist/actions/dict.js.map +1 -1
- package/dist/actions/updateStructure.d.ts.map +1 -1
- package/dist/actions/updateStructure.js.map +1 -1
- package/dist/components/container/DivContainer.d.ts.map +1 -1
- package/dist/components/container/DivContainer.js +3 -5
- package/dist/components/container/DivContainer.js.map +1 -1
- package/dist/components/image/DivImage.d.ts.map +1 -1
- package/dist/components/image/DivImage.js +1 -6
- package/dist/components/image/DivImage.js.map +1 -1
- package/dist/components/state/DivState.d.ts.map +1 -1
- package/dist/components/state/DivState.js +3 -5
- package/dist/components/state/DivState.js.map +1 -1
- package/dist/components/text/DivText.d.ts.map +1 -1
- package/dist/components/text/DivText.js +4 -4
- package/dist/components/text/DivText.js.map +1 -1
- package/dist/components/utilities/Background.d.ts +11 -0
- package/dist/components/utilities/Background.d.ts.map +1 -0
- package/dist/components/utilities/Background.js +73 -0
- package/dist/components/utilities/Background.js.map +1 -0
- package/dist/components/utilities/Outer.d.ts.map +1 -1
- package/dist/components/utilities/Outer.js +24 -10
- package/dist/components/utilities/Outer.js.map +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js.map +1 -1
- package/dist/expressions/eval.d.ts.map +1 -1
- package/dist/expressions/eval.js +19 -11
- package/dist/expressions/eval.js.map +1 -1
- package/dist/expressions/funcs/array.d.ts.map +1 -1
- package/dist/expressions/funcs/array.js +72 -168
- package/dist/expressions/funcs/array.js.map +1 -1
- package/dist/expressions/funcs/colors.d.ts.map +1 -1
- package/dist/expressions/funcs/colors.js.map +1 -1
- package/dist/expressions/funcs/customFuncs.d.ts.map +1 -1
- package/dist/expressions/funcs/customFuncs.js +6 -4
- package/dist/expressions/funcs/customFuncs.js.map +1 -1
- package/dist/expressions/funcs/datetime.d.ts.map +1 -1
- package/dist/expressions/funcs/datetime.js +1 -1
- package/dist/expressions/funcs/datetime.js.map +1 -1
- package/dist/expressions/funcs/dict.d.ts.map +1 -1
- package/dist/expressions/funcs/dict.js.map +1 -1
- package/dist/expressions/funcs/funcs.d.ts.map +1 -1
- package/dist/expressions/funcs/funcs.js +21 -13
- package/dist/expressions/funcs/funcs.js.map +1 -1
- package/dist/expressions/funcs/math.d.ts.map +1 -1
- package/dist/expressions/funcs/math.js +40 -20
- package/dist/expressions/funcs/math.js.map +1 -1
- package/dist/expressions/funcs/std.d.ts.map +1 -1
- package/dist/expressions/funcs/std.js +4 -4
- package/dist/expressions/funcs/std.js.map +1 -1
- package/dist/expressions/funcs/strings.d.ts.map +1 -1
- package/dist/expressions/funcs/strings.js +1 -2
- package/dist/expressions/funcs/strings.js.map +1 -1
- package/dist/expressions/funcs/trigonometry.js +2 -2
- package/dist/expressions/funcs/trigonometry.js.map +1 -1
- package/dist/expressions/json.d.ts +2 -2
- package/dist/expressions/json.d.ts.map +1 -1
- package/dist/expressions/json.js +6 -4
- package/dist/expressions/json.js.map +1 -1
- package/dist/expressions/utils.d.ts.map +1 -1
- package/dist/expressions/utils.js +9 -10
- package/dist/expressions/utils.js.map +1 -1
- package/dist/expressions/variable.d.ts.map +1 -1
- package/dist/expressions/variable.js +3 -7
- package/dist/expressions/variable.js.map +1 -1
- package/dist/expressions/walk.d.ts.map +1 -1
- package/dist/expressions/walk.js.map +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useAction.d.ts.map +1 -1
- package/dist/hooks/useAction.js.map +1 -1
- package/dist/hooks/useDerivedFromVars.d.ts.map +1 -1
- package/dist/hooks/useDerivedFromVars.js.map +1 -1
- package/dist/hooks/useVariable.d.ts.map +1 -1
- package/dist/hooks/useVariable.js +4 -4
- package/dist/hooks/useVariable.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/stores/createObservable.d.ts.map +1 -1
- package/dist/stores/createObservable.js.map +1 -1
- package/dist/utils/applyTemplate.d.ts +2 -2
- package/dist/utils/applyTemplate.d.ts.map +1 -1
- package/dist/utils/applyTemplate.js +13 -13
- package/dist/utils/applyTemplate.js.map +1 -1
- package/dist/utils/correctColor.d.ts.map +1 -1
- package/dist/utils/correctColor.js +8 -6
- package/dist/utils/correctColor.js.map +1 -1
- package/dist/utils/formatDate.d.ts.map +1 -1
- package/dist/utils/formatDate.js +7 -10
- package/dist/utils/formatDate.js.map +1 -1
- package/dist/utils/wrapError.d.ts.map +1 -1
- package/dist/utils/wrapError.js.map +1 -1
- package/package.json +8 -7
- package/src/DivKit.tsx +258 -220
- package/src/actions/array.ts +91 -64
- package/src/actions/copyToClipboard.ts +28 -19
- package/src/actions/dict.ts +36 -26
- package/src/actions/updateStructure.ts +86 -61
- package/src/components/README.md +38 -18
- package/src/components/container/DivContainer.tsx +4 -14
- package/src/components/image/DivImage.tsx +1 -11
- package/src/components/state/DivState.tsx +3 -9
- package/src/components/text/DivText.tsx +8 -20
- package/src/components/utilities/Background.tsx +120 -0
- package/src/components/utilities/Outer.tsx +24 -23
- package/src/components/utilities/README.md +37 -32
- package/src/context/index.ts +2 -11
- package/src/expressions/ast.d.ts +16 -9
- package/src/expressions/eval.ts +82 -37
- package/src/expressions/funcs/array.ts +129 -209
- package/src/expressions/funcs/colors.ts +1 -3
- package/src/expressions/funcs/customFuncs.ts +6 -4
- package/src/expressions/funcs/datetime.ts +10 -3
- package/src/expressions/funcs/dict.ts +16 -2
- package/src/expressions/funcs/funcs.ts +75 -89
- package/src/expressions/funcs/math.ts +103 -43
- package/src/expressions/funcs/std.ts +4 -7
- package/src/expressions/funcs/strings.ts +9 -25
- package/src/expressions/funcs/trigonometry.ts +2 -2
- package/src/expressions/json.ts +60 -53
- package/src/expressions/utils.ts +24 -22
- package/src/expressions/variable.ts +5 -21
- package/src/expressions/walk.ts +6 -3
- package/src/hooks/README.md +61 -53
- package/src/hooks/index.ts +3 -18
- package/src/hooks/useAction.ts +1 -3
- package/src/hooks/useDerivedFromVars.ts +3 -13
- package/src/hooks/useVariable.ts +7 -17
- package/src/index.ts +10 -48
- package/src/stores/createObservable.ts +35 -35
- package/src/types/alignment.d.ts +15 -6
- package/src/types/background.d.ts +6 -2
- package/src/types/base.d.ts +41 -9
- package/src/types/componentContext.d.ts +27 -22
- package/src/types/container.d.ts +1 -4
- package/src/types/text.d.ts +1 -1
- package/src/utils/applyTemplate.ts +103 -109
- package/src/utils/correctColor.ts +9 -8
- package/src/utils/formatDate.ts +175 -86
- package/src/utils/wrapError.ts +7 -4
package/src/components/README.md
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
## MVP Components Implemented
|
|
4
4
|
|
|
5
5
|
### 1. DivText (`text/DivText.tsx`)
|
|
6
|
+
|
|
6
7
|
Text rendering component with variable substitution and styling.
|
|
7
8
|
|
|
8
9
|
**Features:**
|
|
10
|
+
|
|
9
11
|
- ✅ Text rendering with variable substitution
|
|
10
12
|
- ✅ Font styling (size, weight, color, family)
|
|
11
13
|
- ✅ Text alignment (horizontal, RTL support)
|
|
@@ -15,6 +17,7 @@ Text rendering component with variable substitution and styling.
|
|
|
15
17
|
- ✅ Font feature settings (basic)
|
|
16
18
|
|
|
17
19
|
**Deferred:**
|
|
20
|
+
|
|
18
21
|
- Text ranges (nested styling)
|
|
19
22
|
- Text images
|
|
20
23
|
- Text gradients
|
|
@@ -23,9 +26,11 @@ Text rendering component with variable substitution and styling.
|
|
|
23
26
|
- Selectable text with custom actions
|
|
24
27
|
|
|
25
28
|
### 2. DivContainer (`container/DivContainer.tsx`)
|
|
29
|
+
|
|
26
30
|
Flex container component for layout management.
|
|
27
31
|
|
|
28
32
|
**Features:**
|
|
33
|
+
|
|
29
34
|
- ✅ Vertical/horizontal/overlap orientation
|
|
30
35
|
- ✅ Content alignment (horizontal & vertical)
|
|
31
36
|
- ✅ Item spacing (gap)
|
|
@@ -33,6 +38,7 @@ Flex container component for layout management.
|
|
|
33
38
|
- ✅ RTL support
|
|
34
39
|
|
|
35
40
|
**Deferred:**
|
|
41
|
+
|
|
36
42
|
- Wrap layout mode
|
|
37
43
|
- Separators (visual dividers)
|
|
38
44
|
- Line separators (for wrap mode)
|
|
@@ -41,9 +47,11 @@ Flex container component for layout management.
|
|
|
41
47
|
- Clip to bounds
|
|
42
48
|
|
|
43
49
|
### 3. DivImage (`image/DivImage.tsx`)
|
|
50
|
+
|
|
44
51
|
Image component with network loading and scaling.
|
|
45
52
|
|
|
46
53
|
**Features:**
|
|
54
|
+
|
|
47
55
|
- ✅ Network image loading
|
|
48
56
|
- ✅ Scaling modes (fill, fit, stretch, no_scale)
|
|
49
57
|
- ✅ Placeholder color while loading
|
|
@@ -52,6 +60,7 @@ Image component with network loading and scaling.
|
|
|
52
60
|
- ✅ Aspect ratio
|
|
53
61
|
|
|
54
62
|
**Deferred:**
|
|
63
|
+
|
|
55
64
|
- GIF support (requires react-native-gif)
|
|
56
65
|
- Image preview (blur-up technique)
|
|
57
66
|
- Tint color and tint modes
|
|
@@ -61,9 +70,11 @@ Image component with network loading and scaling.
|
|
|
61
70
|
- react-native-fast-image integration
|
|
62
71
|
|
|
63
72
|
### 4. DivState (`state/DivState.tsx`)
|
|
73
|
+
|
|
64
74
|
State management component for switching between different UI states.
|
|
65
75
|
|
|
66
76
|
**Features:**
|
|
77
|
+
|
|
67
78
|
- ✅ State selection by state_id
|
|
68
79
|
- ✅ Default state
|
|
69
80
|
- ✅ State switching via actions (set_state)
|
|
@@ -72,6 +83,7 @@ State management component for switching between different UI states.
|
|
|
72
83
|
- ✅ Two-way binding with variables
|
|
73
84
|
|
|
74
85
|
**Deferred:**
|
|
86
|
+
|
|
75
87
|
- Transition animations (in/out/change)
|
|
76
88
|
- Animation timing and interpolation
|
|
77
89
|
- Clip to bounds
|
|
@@ -79,15 +91,18 @@ State management component for switching between different UI states.
|
|
|
79
91
|
- Multiple concurrent state transitions
|
|
80
92
|
|
|
81
93
|
### 5. DivComponent (`DivComponent.tsx`)
|
|
94
|
+
|
|
82
95
|
Universal component router that dispatches to appropriate component based on type.
|
|
83
96
|
|
|
84
97
|
**Supported Types:**
|
|
98
|
+
|
|
85
99
|
- `text` → DivText
|
|
86
100
|
- `container` → DivContainer
|
|
87
101
|
- `image` / `gif` → DivImage
|
|
88
102
|
- `state` → DivState
|
|
89
103
|
|
|
90
104
|
**Deferred Types:**
|
|
105
|
+
|
|
91
106
|
- `gallery`, `pager`, `tabs`
|
|
92
107
|
- `slider`, `indicator`
|
|
93
108
|
- `input`, `select`, `switch`
|
|
@@ -97,9 +112,11 @@ Universal component router that dispatches to appropriate component based on typ
|
|
|
97
112
|
## Utility Components
|
|
98
113
|
|
|
99
114
|
### Outer (`utilities/Outer.tsx`)
|
|
115
|
+
|
|
100
116
|
Base wrapper component providing common functionality for all components.
|
|
101
117
|
|
|
102
118
|
**Features:**
|
|
119
|
+
|
|
103
120
|
- Visibility handling (visible/invisible/gone)
|
|
104
121
|
- Sizing (width/height with fixed/match_parent/wrap_content)
|
|
105
122
|
- Padding and margins
|
|
@@ -110,6 +127,7 @@ Base wrapper component providing common functionality for all components.
|
|
|
110
127
|
- Action handling (onPress)
|
|
111
128
|
|
|
112
129
|
### Unknown (`utilities/Unknown.tsx`)
|
|
130
|
+
|
|
113
131
|
Fallback component for unsupported types.
|
|
114
132
|
|
|
115
133
|
## Architecture
|
|
@@ -131,6 +149,7 @@ DivComponent (router)
|
|
|
131
149
|
## Integration with Context System
|
|
132
150
|
|
|
133
151
|
All components integrate with:
|
|
152
|
+
|
|
134
153
|
- **DivKitContext**: Access to variables, actions, configuration
|
|
135
154
|
- **StateContext**: State management and transitions
|
|
136
155
|
- **ActionContext**: Action execution
|
|
@@ -139,6 +158,7 @@ All components integrate with:
|
|
|
139
158
|
## Integration with Hooks
|
|
140
159
|
|
|
141
160
|
All components use reactive hooks:
|
|
161
|
+
|
|
142
162
|
- `useDerivedFromVarsSimple`: Variable substitution
|
|
143
163
|
- `useAction`, `useActionHandler`: Action execution
|
|
144
164
|
- `useDivKitContext`, `useStateContext`: Context access
|
|
@@ -149,29 +169,29 @@ All components use reactive hooks:
|
|
|
149
169
|
import { DivComponent } from 'react-native-divkit';
|
|
150
170
|
|
|
151
171
|
const json = {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
172
|
+
type: 'container',
|
|
173
|
+
orientation: 'vertical',
|
|
174
|
+
items: [
|
|
175
|
+
{
|
|
176
|
+
type: 'text',
|
|
177
|
+
text: 'Hello @{userName}!',
|
|
178
|
+
font_size: 24
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
type: 'image',
|
|
182
|
+
image_url: 'https://example.com/image.png',
|
|
183
|
+
scale: 'fit'
|
|
184
|
+
}
|
|
185
|
+
]
|
|
166
186
|
};
|
|
167
187
|
|
|
168
188
|
const componentContext = {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
189
|
+
json,
|
|
190
|
+
variables: variablesMap
|
|
191
|
+
// ... other context props
|
|
172
192
|
};
|
|
173
193
|
|
|
174
|
-
<DivComponent componentContext={componentContext}
|
|
194
|
+
<DivComponent componentContext={componentContext} />;
|
|
175
195
|
```
|
|
176
196
|
|
|
177
197
|
## Next Steps (Phase 6)
|
|
@@ -50,10 +50,7 @@ export function DivContainer({ componentContext }: DivContainerProps) {
|
|
|
50
50
|
variables || new Map()
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
-
const itemSpacing = useDerivedFromVarsSimple<number>(
|
|
54
|
-
json.item_spacing || 0,
|
|
55
|
-
variables || new Map()
|
|
56
|
-
);
|
|
53
|
+
const itemSpacing = useDerivedFromVarsSimple<number>(json.item_spacing || 0, variables || new Map());
|
|
57
54
|
|
|
58
55
|
// Build container style
|
|
59
56
|
const containerStyle = useMemo((): ViewStyle => {
|
|
@@ -120,19 +117,14 @@ export function DivContainer({ componentContext }: DivContainerProps) {
|
|
|
120
117
|
|
|
121
118
|
return json.items.map((item, index) => {
|
|
122
119
|
const childContext = componentContext.produceChildContext(item, {
|
|
123
|
-
path: index
|
|
120
|
+
path: index
|
|
124
121
|
});
|
|
125
122
|
|
|
126
123
|
if (!childContext) {
|
|
127
124
|
return null;
|
|
128
125
|
}
|
|
129
126
|
|
|
130
|
-
const child =
|
|
131
|
-
<DivComponent
|
|
132
|
-
key={item.id || `item-${index}`}
|
|
133
|
-
componentContext={childContext}
|
|
134
|
-
/>
|
|
135
|
-
);
|
|
127
|
+
const child = <DivComponent key={item.id || `item-${index}`} componentContext={childContext} />;
|
|
136
128
|
|
|
137
129
|
// Wrap in positioned View for overlap mode
|
|
138
130
|
if (orientation === 'overlap' && childWrapperStyle) {
|
|
@@ -149,9 +141,7 @@ export function DivContainer({ componentContext }: DivContainerProps) {
|
|
|
149
141
|
|
|
150
142
|
return (
|
|
151
143
|
<Outer componentContext={componentContext}>
|
|
152
|
-
<View style={containerStyle}>
|
|
153
|
-
{renderChildren()}
|
|
154
|
-
</View>
|
|
144
|
+
<View style={containerStyle}>{renderChildren()}</View>
|
|
155
145
|
</Outer>
|
|
156
146
|
);
|
|
157
147
|
}
|
|
@@ -43,10 +43,7 @@ export function DivImage({ componentContext }: DivImageProps) {
|
|
|
43
43
|
variables || new Map()
|
|
44
44
|
);
|
|
45
45
|
|
|
46
|
-
const scale = useDerivedFromVarsSimple<ImageScale>(
|
|
47
|
-
json.scale || 'fill',
|
|
48
|
-
variables || new Map()
|
|
49
|
-
);
|
|
46
|
+
const scale = useDerivedFromVarsSimple<ImageScale>(json.scale || 'fill', variables || new Map());
|
|
50
47
|
|
|
51
48
|
const placeholderColor = useDerivedFromVarsSimple<string | undefined>(
|
|
52
49
|
json.placeholder_color,
|
|
@@ -103,12 +100,6 @@ export function DivImage({ componentContext }: DivImageProps) {
|
|
|
103
100
|
return style;
|
|
104
101
|
}, [json.aspect]);
|
|
105
102
|
|
|
106
|
-
// Handle image load events
|
|
107
|
-
const handleLoadStart = () => {
|
|
108
|
-
setLoading(true);
|
|
109
|
-
setError(false);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
103
|
const handleLoadEnd = () => {
|
|
113
104
|
setLoading(false);
|
|
114
105
|
};
|
|
@@ -146,7 +137,6 @@ export function DivImage({ componentContext }: DivImageProps) {
|
|
|
146
137
|
source={{ uri: imageUrl }}
|
|
147
138
|
style={imageStyle}
|
|
148
139
|
resizeMode={resizeMode}
|
|
149
|
-
onLoadStart={handleLoadStart}
|
|
150
140
|
onLoadEnd={handleLoadEnd}
|
|
151
141
|
onError={handleError}
|
|
152
142
|
/>
|
|
@@ -116,7 +116,7 @@ export function DivState({ componentContext }: DivStateProps) {
|
|
|
116
116
|
if (!currentState?.div) return undefined;
|
|
117
117
|
|
|
118
118
|
return componentContext.produceChildContext(currentState.div, {
|
|
119
|
-
path: currentStateId
|
|
119
|
+
path: currentStateId
|
|
120
120
|
});
|
|
121
121
|
}, [currentState, currentStateId, componentContext]);
|
|
122
122
|
|
|
@@ -129,18 +129,12 @@ export function DivState({ componentContext }: DivStateProps) {
|
|
|
129
129
|
// Import DivComponent dynamically to avoid circular dependency
|
|
130
130
|
const DivComponent = require('../DivComponent').DivComponent;
|
|
131
131
|
|
|
132
|
-
return
|
|
133
|
-
<DivComponent
|
|
134
|
-
componentContext={childContext}
|
|
135
|
-
/>
|
|
136
|
-
);
|
|
132
|
+
return <DivComponent componentContext={childContext} />;
|
|
137
133
|
};
|
|
138
134
|
|
|
139
135
|
return (
|
|
140
136
|
<Outer componentContext={componentContext}>
|
|
141
|
-
<View>
|
|
142
|
-
{renderContent()}
|
|
143
|
-
</View>
|
|
137
|
+
<View>{renderContent()}</View>
|
|
144
138
|
</Outer>
|
|
145
139
|
);
|
|
146
140
|
}
|
|
@@ -35,30 +35,18 @@ export function DivText({ componentContext }: DivTextProps) {
|
|
|
35
35
|
const { json, variables } = componentContext;
|
|
36
36
|
|
|
37
37
|
// Reactive properties - use hooks for properties that may contain variables
|
|
38
|
-
const text = useDerivedFromVarsSimple<string>(
|
|
39
|
-
json.text || '',
|
|
40
|
-
variables || new Map()
|
|
41
|
-
);
|
|
38
|
+
const text = useDerivedFromVarsSimple<string>(json.text || '', variables || new Map());
|
|
42
39
|
|
|
43
|
-
const fontSize = useDerivedFromVarsSimple<number>(
|
|
44
|
-
json.font_size || 12,
|
|
45
|
-
variables || new Map()
|
|
46
|
-
);
|
|
40
|
+
const fontSize = useDerivedFromVarsSimple<number>(json.font_size || 12, variables || new Map());
|
|
47
41
|
|
|
48
|
-
const textColor = useDerivedFromVarsSimple<string>(
|
|
49
|
-
json.text_color || '#000000',
|
|
50
|
-
variables || new Map()
|
|
51
|
-
);
|
|
42
|
+
const textColor = useDerivedFromVarsSimple<string>(json.text_color || '#000000', variables || new Map());
|
|
52
43
|
|
|
53
44
|
const textAlignmentHorizontal = useDerivedFromVarsSimple(
|
|
54
45
|
json.text_alignment_horizontal || 'start',
|
|
55
46
|
variables || new Map()
|
|
56
47
|
);
|
|
57
48
|
|
|
58
|
-
const maxLines = useDerivedFromVarsSimple<number | undefined>(
|
|
59
|
-
json.max_lines,
|
|
60
|
-
variables || new Map()
|
|
61
|
-
);
|
|
49
|
+
const maxLines = useDerivedFromVarsSimple<number | undefined>(json.max_lines, variables || new Map());
|
|
62
50
|
|
|
63
51
|
// Build text style
|
|
64
52
|
const textStyle = useMemo((): TextStyle => {
|
|
@@ -77,10 +65,10 @@ export function DivText({ componentContext }: DivTextProps) {
|
|
|
77
65
|
// Font weight
|
|
78
66
|
if (json.font_weight) {
|
|
79
67
|
const weightMap: Record<FontWeight, TextStyle['fontWeight']> = {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
68
|
+
light: '300',
|
|
69
|
+
regular: '400',
|
|
70
|
+
medium: '500',
|
|
71
|
+
bold: '700'
|
|
84
72
|
};
|
|
85
73
|
style.fontWeight = weightMap[json.font_weight] || '400';
|
|
86
74
|
} else if (json.font_weight_value) {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet, View, ViewStyle } from 'react-native';
|
|
3
|
+
import Svg, { Defs, RadialGradient, Stop, Rect } from 'react-native-svg';
|
|
4
|
+
import type { Background as BackgroundType, RadialBackground } from '../../types/background';
|
|
5
|
+
|
|
6
|
+
export interface BackgroundProps {
|
|
7
|
+
layers?: BackgroundType[];
|
|
8
|
+
style?: ViewStyle;
|
|
9
|
+
width?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const RadialGradientLayer = ({ layer }: { layer: RadialBackground }) => {
|
|
14
|
+
// Default to 50% 50% if not specified
|
|
15
|
+
let cx = '50%';
|
|
16
|
+
let cy = '50%';
|
|
17
|
+
|
|
18
|
+
if (layer.center_x) {
|
|
19
|
+
if (layer.center_x.type === 'fixed') {
|
|
20
|
+
cx = `${layer.center_x.value}`;
|
|
21
|
+
} else {
|
|
22
|
+
cx = `${layer.center_x.value * 100}%`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (layer.center_y) {
|
|
27
|
+
if (layer.center_y.type === 'fixed') {
|
|
28
|
+
cy = `${layer.center_y.value}`;
|
|
29
|
+
} else {
|
|
30
|
+
cy = `${layer.center_y.value * 100}%`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Colors
|
|
35
|
+
// If colors array provided, distribute evenly
|
|
36
|
+
// If color_map provided, use it
|
|
37
|
+
let stops: JSX.Element[] = [];
|
|
38
|
+
|
|
39
|
+
if (layer.colors) {
|
|
40
|
+
stops = layer.colors.map((color, index) => (
|
|
41
|
+
<Stop
|
|
42
|
+
key={index}
|
|
43
|
+
offset={index / (layer.colors!.length - 1)}
|
|
44
|
+
stopColor={color}
|
|
45
|
+
stopOpacity={1}
|
|
46
|
+
/>
|
|
47
|
+
));
|
|
48
|
+
} else if (layer.color_map) {
|
|
49
|
+
stops = layer.color_map.map((point, index) => (
|
|
50
|
+
<Stop
|
|
51
|
+
key={index}
|
|
52
|
+
offset={point.position}
|
|
53
|
+
stopColor={point.color}
|
|
54
|
+
stopOpacity={1}
|
|
55
|
+
/>
|
|
56
|
+
));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Radius
|
|
60
|
+
// DivKit defaults: farthest_corner
|
|
61
|
+
// SVG RadialGradient rx ry defaults to 50%
|
|
62
|
+
// To support "farthest_corner" accurately we might need complex math or just use a large radius like 100%?
|
|
63
|
+
// For now, let's stick to 50% (containing circle) or 100%?
|
|
64
|
+
// A safe default for radial gradients covering a view is often 50% rx/ry if the center is center.
|
|
65
|
+
// If the center is custom, we might need adjustments.
|
|
66
|
+
// Let's use '50%' for rx/ry which is standard for "closest-side" sort of.
|
|
67
|
+
// Specifying units="userSpaceOnUse" allows pixel values.
|
|
68
|
+
// Specifying units="objectBoundingBox" (default) allows percentages.
|
|
69
|
+
|
|
70
|
+
// We'll use objectBoundingBox
|
|
71
|
+
const rx = '50%';
|
|
72
|
+
const ry = '50%';
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Svg height="100%" width="100%" style={StyleSheet.absoluteFill}>
|
|
76
|
+
<Defs>
|
|
77
|
+
<RadialGradient
|
|
78
|
+
id="grad"
|
|
79
|
+
cx={cx}
|
|
80
|
+
cy={cy}
|
|
81
|
+
rx={rx}
|
|
82
|
+
ry={ry}
|
|
83
|
+
fx={cx}
|
|
84
|
+
fy={cy}
|
|
85
|
+
gradientUnits="objectBoundingBox"
|
|
86
|
+
>
|
|
87
|
+
{stops}
|
|
88
|
+
</RadialGradient>
|
|
89
|
+
</Defs>
|
|
90
|
+
<Rect x="0" y="0" width="100%" height="100%" fill="url(#grad)" />
|
|
91
|
+
</Svg>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const Background = ({ layers, style }: BackgroundProps) => {
|
|
96
|
+
if (!layers || layers.length === 0) return null;
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<View style={[StyleSheet.absoluteFill, style, { zIndex: -1, overflow: 'hidden' }]} pointerEvents="none">
|
|
100
|
+
{layers.map((layer, index) => {
|
|
101
|
+
if (layer.type === 'solid') {
|
|
102
|
+
return (
|
|
103
|
+
<View
|
|
104
|
+
key={index}
|
|
105
|
+
style={[StyleSheet.absoluteFill, { backgroundColor: layer.color }]}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
if (layer.type === 'radial_gradient') {
|
|
110
|
+
return (
|
|
111
|
+
<View key={index} style={StyleSheet.absoluteFill}>
|
|
112
|
+
<RadialGradientLayer layer={layer} />
|
|
113
|
+
</View>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
})}
|
|
118
|
+
</View>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
@@ -8,6 +8,7 @@ import type { MaybeMissing } from '../../expressions/json';
|
|
|
8
8
|
import { useDerivedFromVarsSimple } from '../../hooks/useDerivedFromVars';
|
|
9
9
|
import { useActionHandler, useHasActions } from '../../hooks/useAction';
|
|
10
10
|
import { useDivKitContext } from '../../context/DivKitContext';
|
|
11
|
+
import { Background } from './Background';
|
|
11
12
|
|
|
12
13
|
export interface OuterProps<T extends DivBaseData = DivBaseData> {
|
|
13
14
|
componentContext: ComponentContext<T>;
|
|
@@ -31,14 +32,8 @@ export function Outer<T extends DivBaseData = DivBaseData>({
|
|
|
31
32
|
|
|
32
33
|
// Only use reactive hooks for truly dynamic properties (visibility, alpha)
|
|
33
34
|
// For MVP, other properties are read directly from JSON (can be enhanced later)
|
|
34
|
-
const visibility = useDerivedFromVarsSimple<Visibility>(
|
|
35
|
-
|
|
36
|
-
variables || new Map()
|
|
37
|
-
);
|
|
38
|
-
const alpha = useDerivedFromVarsSimple<number>(
|
|
39
|
-
json.alpha !== undefined ? json.alpha : 1,
|
|
40
|
-
variables || new Map()
|
|
41
|
-
);
|
|
35
|
+
const visibility = useDerivedFromVarsSimple<Visibility>(json.visibility || 'visible', variables || new Map());
|
|
36
|
+
const alpha = useDerivedFromVarsSimple<number>(json.alpha !== undefined ? json.alpha : 1, variables || new Map());
|
|
42
37
|
|
|
43
38
|
// Extract properties directly from JSON for MVP (non-reactive)
|
|
44
39
|
const paddings = json.paddings;
|
|
@@ -76,7 +71,10 @@ export function Outer<T extends DivBaseData = DivBaseData>({
|
|
|
76
71
|
if (widthVal.type === 'fixed') {
|
|
77
72
|
styles.width = (widthVal as FixedSize).value;
|
|
78
73
|
} else if (widthVal.type === 'match_parent') {
|
|
79
|
-
|
|
74
|
+
// Use alignSelf: 'stretch' instead of width: '100%' so that
|
|
75
|
+
// margins are subtracted from the available space rather than
|
|
76
|
+
// added on top of 100%, which would cause overflow.
|
|
77
|
+
styles.alignSelf = 'stretch';
|
|
80
78
|
styles.flexGrow = (widthVal as MatchParentSize).weight || 1;
|
|
81
79
|
} else if (widthVal.type === 'wrap_content') {
|
|
82
80
|
styles.alignSelf = 'flex-start';
|
|
@@ -84,7 +82,7 @@ export function Outer<T extends DivBaseData = DivBaseData>({
|
|
|
84
82
|
}
|
|
85
83
|
} else {
|
|
86
84
|
// Default: match_parent
|
|
87
|
-
styles.
|
|
85
|
+
styles.alignSelf = 'stretch';
|
|
88
86
|
styles.flexGrow = 1;
|
|
89
87
|
}
|
|
90
88
|
|
|
@@ -148,15 +146,8 @@ export function Outer<T extends DivBaseData = DivBaseData>({
|
|
|
148
146
|
}
|
|
149
147
|
}
|
|
150
148
|
|
|
151
|
-
// Background
|
|
152
|
-
|
|
153
|
-
const bg = background as any[];
|
|
154
|
-
const solidBg = bg.find((b: any) => b?.type === 'solid');
|
|
155
|
-
if (solidBg && solidBg.color) {
|
|
156
|
-
styles.backgroundColor = solidBg.color;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
149
|
+
// Background handled by Background component
|
|
150
|
+
|
|
160
151
|
// Border
|
|
161
152
|
if (border) {
|
|
162
153
|
const b = border as any;
|
|
@@ -219,13 +210,22 @@ export function Outer<T extends DivBaseData = DivBaseData>({
|
|
|
219
210
|
return StyleSheet.flatten([containerStyle, customStyle]);
|
|
220
211
|
}, [containerStyle, customStyle]);
|
|
221
212
|
|
|
213
|
+
const borderStyle = useMemo(() => {
|
|
214
|
+
const s = finalStyle || {};
|
|
215
|
+
const res: ViewStyle = {};
|
|
216
|
+
if (s.borderRadius) res.borderRadius = s.borderRadius;
|
|
217
|
+
if (s.borderTopLeftRadius) res.borderTopLeftRadius = s.borderTopLeftRadius;
|
|
218
|
+
if (s.borderTopRightRadius) res.borderTopRightRadius = s.borderTopRightRadius;
|
|
219
|
+
if (s.borderBottomLeftRadius) res.borderBottomLeftRadius = s.borderBottomLeftRadius;
|
|
220
|
+
if (s.borderBottomRightRadius) res.borderBottomRightRadius = s.borderBottomRightRadius;
|
|
221
|
+
return res;
|
|
222
|
+
}, [finalStyle]);
|
|
223
|
+
|
|
222
224
|
// Render with or without Pressable based on actions
|
|
223
225
|
if (hasActions) {
|
|
224
226
|
return (
|
|
225
|
-
<Pressable
|
|
226
|
-
|
|
227
|
-
style={finalStyle}
|
|
228
|
-
>
|
|
227
|
+
<Pressable onPress={handlePress} style={finalStyle}>
|
|
228
|
+
<Background layers={background as any} style={borderStyle} />
|
|
229
229
|
{children}
|
|
230
230
|
</Pressable>
|
|
231
231
|
);
|
|
@@ -233,6 +233,7 @@ export function Outer<T extends DivBaseData = DivBaseData>({
|
|
|
233
233
|
|
|
234
234
|
return (
|
|
235
235
|
<View style={finalStyle}>
|
|
236
|
+
<Background layers={background as any} style={borderStyle} />
|
|
236
237
|
{children}
|
|
237
238
|
</View>
|
|
238
239
|
);
|