@ea-lab/reactive-json-docs 0.1.11 → 0.2.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/package.json +2 -2
- package/public/rjbuild/docs/core/element/special/ReactiveJsonSubroot.md +304 -9
- package/public/rjbuild/docs/core/element/special/ReactiveJsonSubroot.yaml +323 -8
- package/public/rjbuild/docs/extend/component-development-guide-llm.md +3 -2
- package/public/rjbuild/docs/extend/component-development.md +1 -1
- package/public/rjbuild/docs/extend/component-development.yaml +1 -1
- package/public/rjbuild/docs/getting-started.md +17 -9
- package/public/rjbuild/docs/getting-started.yaml +12 -8
- package/public/rjbuild/docs/install.yaml +0 -1
- package/public/rjbuild/docs/template.md +119 -24
- package/public/rjbuild/docs/template.yaml +141 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ea-lab/reactive-json-docs",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Complete documentation for Reactive-JSON - Components, examples and LLM-parsable guides",
|
|
5
5
|
"main": "public/rjbuild/docs/index.yaml",
|
|
6
6
|
"files": [
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"private": false,
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@craco/craco": "^7.1.0",
|
|
29
|
-
"@ea-lab/reactive-json": "^0.0
|
|
29
|
+
"@ea-lab/reactive-json": "^0.1.0",
|
|
30
30
|
"@ea-lab/reactive-json-chartjs": "^0.0.23",
|
|
31
31
|
"@npmcli/fs": "^4.0.0",
|
|
32
32
|
"@reduxjs/toolkit": "^2.6.1",
|
|
@@ -4,17 +4,133 @@
|
|
|
4
4
|
|
|
5
5
|
The `ReactiveJsonSubroot` component allows you to render a new Reactive-JSON root inside an existing application. It is useful for embedding a sub-application, isolating a part of the data tree, or rendering a separate rjbuild with its own options.
|
|
6
6
|
|
|
7
|
+
With the `sharedUpdates` feature, the component can also propagate data changes back to the parent, enabling seamless communication between parent and subroot when working with shared data references.
|
|
8
|
+
|
|
7
9
|
## Properties
|
|
8
|
-
- `rjOptions` (object, required): Options to pass to the subroot
|
|
9
|
-
-
|
|
10
|
+
- `rjOptions` (object, required): Options to pass to the subroot - accepts **all** `ReactiveJsonRoot` properties including:
|
|
11
|
+
- `rjBuildUrl`: URL to load the RjBuild from.
|
|
12
|
+
- `rjBuildFetchMethod`: HTTP method ("GET" or "POST").
|
|
13
|
+
- `headersForRjBuild`: Headers for the request.
|
|
14
|
+
- `dataOverride`: Override data for the loaded/defined RjBuild.
|
|
15
|
+
- `maybeRawAppRjBuild`: Inline RjBuild content (string or object) containing:
|
|
16
|
+
- `renderView`: View definition.
|
|
17
|
+
- `templates`: Template definitions.
|
|
18
|
+
- `data`: Initial data.
|
|
19
|
+
- `debugMode`: Enable debug mode and related wrapper components.
|
|
20
|
+
- `sharedUpdates` (boolean, optional): Enable upstream data propagation to parent (default: false).
|
|
21
|
+
- `dataOverrideEvaluationDepth` (number, optional): Special evaluation depth for dataOverride property.
|
|
22
|
+
- `actions` (array, optional): Action components to apply (passed to `ActionDependant` wrapper).
|
|
23
|
+
- Other standard component properties (e.g., `attributes`) are passed to the `ActionDependant` wrapper.
|
|
10
24
|
|
|
11
25
|
## Behavior
|
|
12
|
-
- Renders a new `ReactiveJsonRoot` with the provided options
|
|
13
|
-
- The subroot is isolated from the parent for data, templates, and rendering
|
|
14
|
-
- Plugins from the parent are reused in the subroot
|
|
15
|
-
-
|
|
26
|
+
- Renders a new `ReactiveJsonRoot` with the provided options.
|
|
27
|
+
- The subroot is typically isolated from the parent for data, templates, and rendering*.
|
|
28
|
+
- Plugins from the parent are automatically reused in the subroot.
|
|
29
|
+
- All properties in `rjOptions` are evaluated with template values using `evaluateTemplateValueCollection()`.
|
|
30
|
+
- If `rjOptions` is not a valid object, nothing is rendered.
|
|
31
|
+
|
|
32
|
+
*_Note: Data isolation is bypassed when `sharedUpdates: true` is enabled, allowing the subroot to propagate data changes back to the parent. Templates and rendering contexts remain isolated._
|
|
33
|
+
|
|
34
|
+
## Shared Updates Feature
|
|
35
|
+
|
|
36
|
+
When `sharedUpdates: true` is enabled, the component automatically detects template references in `dataOverride` and creates update callbacks to propagate changes back to the parent.
|
|
37
|
+
|
|
38
|
+
**Data flow**: Parent data flows to subroot via `dataOverride` → Subroot changes flow back to parent via `sharedUpdates`
|
|
39
|
+
|
|
40
|
+
### How it works
|
|
41
|
+
1. **Automatic analysis**: The system analyzes `dataOverride` to detect references (`~~.`, `~.`, `~>`) to parent data
|
|
42
|
+
2. **Callback creation**: For each detected reference, an update callback is created
|
|
43
|
+
3. **Update interception**: When the subroot modifies data, the system checks if it corresponds to a parent reference
|
|
44
|
+
4. **Propagation**: If so, the update is propagated to the parent instead of being applied locally
|
|
45
|
+
|
|
46
|
+
**Important**: Only data changes are shared. Templates, rendering contexts, and component state remain isolated between parent and subroot.
|
|
47
|
+
|
|
48
|
+
### Advantages
|
|
49
|
+
1. **Automatic synchronization**: Data remains consistent between parent and subroot
|
|
50
|
+
2. **Simplicity**: No need to manually manage update callbacks
|
|
51
|
+
3. **Performance**: Avoids unnecessary re-renders by propagating directly to the right level
|
|
52
|
+
4. **Flexibility**: Supports different referencing patterns (~~., ~., ~>) and arrays containing references
|
|
53
|
+
|
|
54
|
+
### Supported reference types
|
|
55
|
+
- `~~.parentData` - Global data references.
|
|
56
|
+
- `~.localData` - Local template context references.
|
|
57
|
+
- `~>key.data` - Hierarchical references.
|
|
58
|
+
- Arrays and nested objects containing references.
|
|
59
|
+
|
|
60
|
+
### Supported vs Unsupported Cases
|
|
61
|
+
|
|
62
|
+
#### ✅ Supported cases
|
|
63
|
+
|
|
64
|
+
##### 1. Direct reference
|
|
65
|
+
```yaml
|
|
66
|
+
dataOverride: ~~.user
|
|
67
|
+
# Modifications in the subroot propagate to "user" in the parent
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
##### 2. Object mapping with references
|
|
71
|
+
```yaml
|
|
72
|
+
dataOverride:
|
|
73
|
+
userInfo: ~~.user
|
|
74
|
+
settings: ~~.config
|
|
75
|
+
# Modifications to "userInfo" propagate to "user" in the parent
|
|
76
|
+
# Modifications to "settings" propagate to "config" in the parent
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
##### 3. Local references
|
|
80
|
+
```yaml
|
|
81
|
+
dataOverride: ~.localData
|
|
82
|
+
# Modifications propagate to the local template context
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
##### 4. Hierarchical references
|
|
86
|
+
```yaml
|
|
87
|
+
dataOverride: ~>key.someData
|
|
88
|
+
# Modifications propagate up the template hierarchy
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
##### 5. Arrays in dataOverride
|
|
92
|
+
```yaml
|
|
93
|
+
dataOverride:
|
|
94
|
+
- ~~.firstItem
|
|
95
|
+
- ~~.secondItem
|
|
96
|
+
# Array items with template references are properly handled
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### ❌ Unsupported cases
|
|
100
|
+
|
|
101
|
+
##### Nested references in data
|
|
102
|
+
```yaml
|
|
103
|
+
dataOverride:
|
|
104
|
+
someProperty: ~~.user
|
|
105
|
+
data:
|
|
106
|
+
someProperty: ~~.anotherProperty # Not supported
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Configuration example
|
|
110
|
+
```yaml
|
|
111
|
+
- type: ReactiveJsonSubroot
|
|
112
|
+
sharedUpdates: true # Enable propagation.
|
|
113
|
+
rjOptions:
|
|
114
|
+
# Option 1: Load from URL with data override.
|
|
115
|
+
rjBuildUrl: "/api/user-form.yaml"
|
|
116
|
+
dataOverride: ~~.user
|
|
117
|
+
headersForRjBuild:
|
|
118
|
+
Authorization: ~~.authToken
|
|
119
|
+
|
|
120
|
+
# Option 2: Inline definition.
|
|
121
|
+
# dataOverride: ~~.user
|
|
122
|
+
# maybeRawAppRjBuild:
|
|
123
|
+
# renderView:
|
|
124
|
+
# form:
|
|
125
|
+
# - type: TextField
|
|
126
|
+
# dataLocation: ~.name
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Examples
|
|
130
|
+
|
|
131
|
+
### Basic subroot from URL
|
|
132
|
+
This example demonstrates the simplest use case: loading and rendering a separate RjBuild file as an isolated subroot. No data sharing occurs between parent and subroot.
|
|
16
133
|
|
|
17
|
-
## Example
|
|
18
134
|
```yaml
|
|
19
135
|
renderView:
|
|
20
136
|
- type: ReactiveJsonSubroot
|
|
@@ -22,6 +138,185 @@ renderView:
|
|
|
22
138
|
rjBuildUrl: "/rjs-build/home.yaml"
|
|
23
139
|
```
|
|
24
140
|
|
|
141
|
+
### Inline definition with shared updates
|
|
142
|
+
This example shows how to create an editable form where changes in the subroot automatically update the parent display. The key feature here is `sharedUpdates: true` which enables data synchronization between the form fields and the parent data display.
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
data:
|
|
146
|
+
user:
|
|
147
|
+
name: "John"
|
|
148
|
+
email: "john@example.com"
|
|
149
|
+
|
|
150
|
+
renderView:
|
|
151
|
+
userDisplay:
|
|
152
|
+
- type: p
|
|
153
|
+
content: ["Name: ", ~~.user.name] # This displays the current user name.
|
|
154
|
+
|
|
155
|
+
editForm:
|
|
156
|
+
- type: ReactiveJsonSubroot
|
|
157
|
+
sharedUpdates: true # Required to update userDisplay when form changes.
|
|
158
|
+
rjOptions:
|
|
159
|
+
dataOverride: ~~.user
|
|
160
|
+
maybeRawAppRjBuild:
|
|
161
|
+
renderView:
|
|
162
|
+
form:
|
|
163
|
+
- type: TextField
|
|
164
|
+
label: "Name"
|
|
165
|
+
dataLocation: ~.name # Changes propagate to ~~.user.name.
|
|
166
|
+
- type: TextField
|
|
167
|
+
label: "Email"
|
|
168
|
+
dataLocation: ~.email # Changes propagate to ~~.user.email.
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Multi-section configuration
|
|
172
|
+
This example demonstrates how to map different parts of the parent data to different sections within the subroot. The `dataOverride` object creates custom mappings (`userProfile` and `userSettings`) that allow the subroot to work with reorganized data while still propagating changes back to their original locations in the parent.
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
data:
|
|
176
|
+
profile: { name: "John", age: 30 }
|
|
177
|
+
settings: { theme: "dark", lang: "en" }
|
|
178
|
+
|
|
179
|
+
renderView:
|
|
180
|
+
editor:
|
|
181
|
+
- type: ReactiveJsonSubroot
|
|
182
|
+
sharedUpdates: true
|
|
183
|
+
rjOptions:
|
|
184
|
+
dataOverride:
|
|
185
|
+
userProfile: ~~.profile
|
|
186
|
+
userSettings: ~~.settings
|
|
187
|
+
maybeRawAppRjBuild:
|
|
188
|
+
renderView:
|
|
189
|
+
sections:
|
|
190
|
+
- type: TextField
|
|
191
|
+
label: "Name"
|
|
192
|
+
dataLocation: ~.userProfile.name
|
|
193
|
+
- type: TextField
|
|
194
|
+
label: "Theme"
|
|
195
|
+
dataLocation: ~.userSettings.theme
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Loading from URL with authentication
|
|
199
|
+
This example shows how to load an external RjBuild file while providing authentication headers and data overrides. The external form loaded from the URL will receive the user profile data and any changes made will be propagated back to the parent thanks to `sharedUpdates`. This pattern is useful for reusable form components that need to work with dynamic data and authentication.
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
data:
|
|
203
|
+
user:
|
|
204
|
+
profile: { name: "John", role: "admin" }
|
|
205
|
+
authToken: "abc123"
|
|
206
|
+
|
|
207
|
+
renderView:
|
|
208
|
+
profileEditor:
|
|
209
|
+
- type: ReactiveJsonSubroot
|
|
210
|
+
sharedUpdates: true
|
|
211
|
+
rjOptions:
|
|
212
|
+
rjBuildUrl: "/forms/user-profile-form.yaml"
|
|
213
|
+
dataOverride: ~~.user.profile
|
|
214
|
+
headersForRjBuild:
|
|
215
|
+
Authorization: ["Bearer ", ~~.authToken]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Array with references
|
|
219
|
+
This example demonstrates how to work with arrays in `dataOverride` where each array item is mapped to different parts of the parent data. The subroot can edit individual array items and changes will be propagated back to their respective locations in the parent array.
|
|
220
|
+
|
|
221
|
+
```yaml
|
|
222
|
+
data:
|
|
223
|
+
items: [
|
|
224
|
+
{ title: "Item 1", active: true },
|
|
225
|
+
{ title: "Item 2", active: false }
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
renderView:
|
|
229
|
+
listEditor:
|
|
230
|
+
- type: ReactiveJsonSubroot
|
|
231
|
+
sharedUpdates: true
|
|
232
|
+
rjOptions:
|
|
233
|
+
dataOverride:
|
|
234
|
+
- ~~.items.0
|
|
235
|
+
- ~~.items.1
|
|
236
|
+
maybeRawAppRjBuild:
|
|
237
|
+
renderView:
|
|
238
|
+
editors:
|
|
239
|
+
- type: TextField
|
|
240
|
+
label: "First item title"
|
|
241
|
+
dataLocation: ~.0.title
|
|
242
|
+
- type: TextField
|
|
243
|
+
label: "Second item title"
|
|
244
|
+
dataLocation: ~.1.title
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Technical Details
|
|
248
|
+
|
|
249
|
+
- Uses `dataLocationToPath()` from the template system for consistent path resolution.
|
|
250
|
+
- Supports all template reference types: `~~.`, `~.`, and `~>`.
|
|
251
|
+
- Handles arrays and nested objects in `dataOverride` when analyzing references.
|
|
252
|
+
- Falls back to local updates if upstream propagation fails.
|
|
253
|
+
- All `rjOptions` properties are evaluated with `evaluateTemplateValueCollection()`.
|
|
254
|
+
- Template evaluation respects the `dataOverrideEvaluationDepth` property for special cases.
|
|
255
|
+
|
|
256
|
+
## Debugging
|
|
257
|
+
|
|
258
|
+
For troubleshooting shared updates:
|
|
259
|
+
|
|
260
|
+
1. **Browser console**: Propagation errors are logged with descriptive messages.
|
|
261
|
+
2. **dataOverride structure**: Ensure template references are valid and exist in parent data.
|
|
262
|
+
3. **Data context**: Verify that referenced data exists in the expected locations.
|
|
263
|
+
4. **Data paths**: Confirm that `dataLocation` values in the subroot match the dataOverride structure.
|
|
264
|
+
|
|
265
|
+
## Caveat: Data Loss Risk with sharedUpdates
|
|
266
|
+
|
|
267
|
+
**⚠️ Important Warning**: When using `sharedUpdates`, there is a risk of data loss in specific scenarios.
|
|
268
|
+
|
|
269
|
+
### The Problem
|
|
270
|
+
If the subroot modifies data that is **not** covered by a template reference from the parent's `dataOverride`, and subsequently the parent re-renders the subroot, the local modifications will be **lost**.
|
|
271
|
+
|
|
272
|
+
### When This Happens
|
|
273
|
+
1. **Subroot modifies local data**: The subroot changes a value that doesn't correspond to any template reference in the parent's `dataOverride`.
|
|
274
|
+
2. **Parent re-renders**: This can occur when:
|
|
275
|
+
- The parent updates itself for any reason.
|
|
276
|
+
- A subroot action triggers an upstream update that causes the parent to re-render.
|
|
277
|
+
3. **Data loss**: The parent's `dataOverride` completely overwrites the subroot's data, erasing local modifications.
|
|
278
|
+
|
|
279
|
+
### Example Scenario
|
|
280
|
+
```yaml
|
|
281
|
+
# Parent has this data structure
|
|
282
|
+
data:
|
|
283
|
+
user: { name: "John", email: "john@example.com" }
|
|
284
|
+
|
|
285
|
+
# Subroot configured like this
|
|
286
|
+
- type: ReactiveJsonSubroot
|
|
287
|
+
sharedUpdates: true
|
|
288
|
+
rjOptions:
|
|
289
|
+
dataOverride: ~~.user # Only user data is referenced
|
|
290
|
+
maybeRawAppRjBuild:
|
|
291
|
+
renderView:
|
|
292
|
+
- type: TextField
|
|
293
|
+
label: "Name"
|
|
294
|
+
dataLocation: ~.name # ✅ Safe - covered by ~~.user
|
|
295
|
+
- type: TextField
|
|
296
|
+
label: "Temporary Note"
|
|
297
|
+
dataLocation: ~.tempNote # ⚠️ Risk - NOT in parent data
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
In this example, if the user types in "Temporary Note" and then any parent update occurs, the `tempNote` value will be lost because it's not part of the original `~~.user` data.
|
|
301
|
+
|
|
302
|
+
### Best Practices to Avoid Data Loss
|
|
303
|
+
1. **Map all needed data**: Ensure all data fields the subroot might modify are included in the parent's data structure.
|
|
304
|
+
2. **Use complete dataOverride**: Include all necessary data paths in your `dataOverride` mapping.
|
|
305
|
+
3. **Avoid local-only modifications**: Design your data flow so that all user inputs correspond to parent data.
|
|
306
|
+
4. **Consider alternatives**: For truly local data, consider using component state or separate data management instead of `sharedUpdates`.
|
|
307
|
+
|
|
25
308
|
## Limitations
|
|
26
|
-
-
|
|
27
|
-
-
|
|
309
|
+
- **Data loss risk**: Local modifications in subroot may be lost when parent re-renders (see Caveat section above).
|
|
310
|
+
- **Nested references in data**: References within references are not supported (e.g., `dataOverride: { prop: "~~.user" }` where data contains `{ prop: "~~.other" }`).
|
|
311
|
+
- **Circular references**: May cause infinite loops if data structures reference each other.
|
|
312
|
+
- **Template isolation**: Templates and rendering contexts remain isolated even with `sharedUpdates`.
|
|
313
|
+
- **Data isolation by default**: Without `sharedUpdates`, data changes in the subroot do not affect the parent.
|
|
314
|
+
- **One-way shared updates**: `sharedUpdates` only propagates changes from subroot to parent, not vice versa.
|
|
315
|
+
- **Backward compatibility**: `sharedUpdates` is disabled by default to maintain existing behavior.
|
|
316
|
+
|
|
317
|
+
## Changelog
|
|
318
|
+
|
|
319
|
+
### reactive-json@0.1.0
|
|
320
|
+
- **New**: `sharedUpdates` feature - enables automatic data synchronization between subroot and parent
|
|
321
|
+
- **New**: `dataOverride` property - allows complete data replacement in subroot with support for template references
|
|
322
|
+
- **New**: Automatic analysis of template references in `dataOverride` for shared updates propagation
|
|
@@ -5,15 +5,88 @@ renderView:
|
|
|
5
5
|
|
|
6
6
|
The `ReactiveJsonSubroot` component allows you to render a new Reactive-JSON root inside an existing application. It is useful for embedding a sub-application, isolating a part of the data tree, or rendering a separate rjbuild with its own options.
|
|
7
7
|
|
|
8
|
+
With the `sharedUpdates` feature, the component can also propagate data changes back to the parent, enabling seamless communication between parent and subroot when working with shared data references.
|
|
9
|
+
|
|
8
10
|
## Properties
|
|
9
|
-
- `rjOptions` (object, required): Options to pass to the subroot
|
|
10
|
-
|
|
11
|
+
- `rjOptions` (object, required): Options to pass to the subroot - accepts **all** `ReactiveJsonRoot` properties.
|
|
12
|
+
- Direct properties: `rjBuildUrl`, `dataOverride`, `headersForRjBuild`, `debugMode`, etc.
|
|
13
|
+
- For inline content: use `maybeRawAppRjBuild` containing `renderView`, `templates`, `data`.
|
|
14
|
+
- `sharedUpdates` (boolean, optional): Enable upstream data propagation to parent (default: false).
|
|
15
|
+
- `dataOverrideEvaluationDepth` (number, optional): Special evaluation depth for dataOverride property.
|
|
16
|
+
- Other properties are passed to the underlying `ActionDependant` wrapper.
|
|
11
17
|
|
|
12
18
|
## Behavior
|
|
13
|
-
- Renders a new `ReactiveJsonRoot` with the provided options
|
|
14
|
-
- The subroot is isolated from the parent for data, templates, and rendering
|
|
15
|
-
- Plugins from the parent are reused in the subroot
|
|
16
|
-
-
|
|
19
|
+
- Renders a new `ReactiveJsonRoot` with the provided options.
|
|
20
|
+
- The subroot is typically isolated from the parent for data, templates, and rendering¹.
|
|
21
|
+
- Plugins from the parent are automatically reused in the subroot.
|
|
22
|
+
- All properties in `rjOptions` are evaluated with template values.
|
|
23
|
+
- If `rjOptions` is not a valid object, nothing is rendered.
|
|
24
|
+
|
|
25
|
+
¹Note: Data isolation is bypassed when `sharedUpdates: true` is enabled, allowing the subroot to propagate data changes back to the parent. Templates and rendering contexts remain isolated.
|
|
26
|
+
|
|
27
|
+
## Shared Updates Feature
|
|
28
|
+
When `sharedUpdates: true` is enabled, the component automatically detects template references in `dataOverride` and creates update callbacks to propagate changes back to the parent.
|
|
29
|
+
|
|
30
|
+
### How it works
|
|
31
|
+
1. **Automatic analysis**: The system analyzes `dataOverride` to detect references (`~~.`, `~.`, `~>`) to parent data
|
|
32
|
+
2. **Callback creation**: For each detected reference, an update callback is created
|
|
33
|
+
3. **Update interception**: When the subroot modifies data, the system checks if it corresponds to a parent reference
|
|
34
|
+
4. **Propagation**: If so, the update is propagated to the parent instead of being applied locally
|
|
35
|
+
|
|
36
|
+
### Advantages
|
|
37
|
+
1. **Automatic synchronization**: Data remains consistent between parent and subroot
|
|
38
|
+
2. **Simplicity**: No need to manually manage update callbacks
|
|
39
|
+
3. **Performance**: Avoids unnecessary re-renders by propagating directly to the right level
|
|
40
|
+
4. **Flexibility**: Supports different referencing patterns (~~., ~., ~>) and arrays containing references
|
|
41
|
+
|
|
42
|
+
### Supported vs Unsupported Cases
|
|
43
|
+
|
|
44
|
+
#### ✅ Supported cases
|
|
45
|
+
|
|
46
|
+
##### 1. Direct reference
|
|
47
|
+
```yaml
|
|
48
|
+
dataOverride: ~~.user
|
|
49
|
+
# Modifications in the subroot propagate to "user" in the parent
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
##### 2. Object mapping with references
|
|
53
|
+
```yaml
|
|
54
|
+
dataOverride:
|
|
55
|
+
userInfo: ~~.user
|
|
56
|
+
settings: ~~.config
|
|
57
|
+
# Modifications to "userInfo" propagate to "user" in the parent
|
|
58
|
+
# Modifications to "settings" propagate to "config" in the parent
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
##### 3. Local references
|
|
62
|
+
```yaml
|
|
63
|
+
dataOverride: ~.localData
|
|
64
|
+
# Modifications propagate to the local template context
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
##### 4. Hierarchical references
|
|
68
|
+
```yaml
|
|
69
|
+
dataOverride: ~>key.someData
|
|
70
|
+
# Modifications propagate up the template hierarchy
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
##### 5. Arrays in dataOverride
|
|
74
|
+
```yaml
|
|
75
|
+
dataOverride:
|
|
76
|
+
- ~~.firstItem
|
|
77
|
+
- ~~.secondItem
|
|
78
|
+
# Array items with template references are properly handled
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### ❌ Unsupported cases
|
|
82
|
+
|
|
83
|
+
##### Nested references in data
|
|
84
|
+
```yaml
|
|
85
|
+
dataOverride:
|
|
86
|
+
someProperty: ~~.user
|
|
87
|
+
data:
|
|
88
|
+
someProperty: ~~.anotherProperty # Not supported
|
|
89
|
+
```
|
|
17
90
|
|
|
18
91
|
- type: RjBuildDescriber
|
|
19
92
|
title: Example
|
|
@@ -44,8 +117,250 @@ renderView:
|
|
|
44
117
|
- type: div
|
|
45
118
|
content: This second subroot is loaded from the "data" key of the main root.
|
|
46
119
|
|
|
120
|
+
- type: RjBuildDescriber
|
|
121
|
+
title: Example with Shared Updates
|
|
122
|
+
description: This example demonstrates the `sharedUpdates` feature where changes in the subroot automatically propagate back to the parent data. Notice how modifying the text field in the subroot will update the display in the parent above it.
|
|
123
|
+
toDescribe:
|
|
124
|
+
data:
|
|
125
|
+
user:
|
|
126
|
+
name: "John Doe"
|
|
127
|
+
email: "john@example.com"
|
|
128
|
+
renderView:
|
|
129
|
+
- type: div
|
|
130
|
+
attributes:
|
|
131
|
+
style:
|
|
132
|
+
padding: "1rem"
|
|
133
|
+
border: "2px solid #007bff"
|
|
134
|
+
borderRadius: "8px"
|
|
135
|
+
backgroundColor: "#f8f9fa"
|
|
136
|
+
marginBottom: "1rem"
|
|
137
|
+
content:
|
|
138
|
+
- type: h4
|
|
139
|
+
content: "Parent Data Display"
|
|
140
|
+
- type: p
|
|
141
|
+
content: ["Name: ", ~~.user.name]
|
|
142
|
+
- type: p
|
|
143
|
+
content: ["Email: ", ~~.user.email]
|
|
144
|
+
|
|
145
|
+
- type: ReactiveJsonSubroot
|
|
146
|
+
sharedUpdates: true
|
|
147
|
+
rjOptions:
|
|
148
|
+
dataOverride: ~~.user
|
|
149
|
+
maybeRawAppRjBuild:
|
|
150
|
+
renderView:
|
|
151
|
+
- type: div
|
|
152
|
+
attributes:
|
|
153
|
+
style:
|
|
154
|
+
padding: "1rem"
|
|
155
|
+
border: "2px solid #28a745"
|
|
156
|
+
borderRadius: "8px"
|
|
157
|
+
backgroundColor: "#e8f5e9"
|
|
158
|
+
content:
|
|
159
|
+
- type: h4
|
|
160
|
+
content: "Subroot Editor (with sharedUpdates)"
|
|
161
|
+
- type: TextField
|
|
162
|
+
label: "Name"
|
|
163
|
+
dataLocation: ~.name
|
|
164
|
+
- type: TextField
|
|
165
|
+
label: "Email"
|
|
166
|
+
dataLocation: ~.email
|
|
167
|
+
- type: p
|
|
168
|
+
attributes:
|
|
169
|
+
style:
|
|
170
|
+
fontSize: "0.9em"
|
|
171
|
+
color: "#666"
|
|
172
|
+
marginTop: "0.5rem"
|
|
173
|
+
content: "Changes here automatically update the parent data above ↑"
|
|
174
|
+
|
|
175
|
+
- type: RjBuildDescriber
|
|
176
|
+
title: Example with Multi-Section Configuration
|
|
177
|
+
description: This example shows how `sharedUpdates` works with complex data mappings where different parts of the parent data are mapped to different sections in the subroot.
|
|
178
|
+
toDescribe:
|
|
179
|
+
data:
|
|
180
|
+
profile:
|
|
181
|
+
name: "Alice Smith"
|
|
182
|
+
age: 28
|
|
183
|
+
settings:
|
|
184
|
+
theme: "dark"
|
|
185
|
+
language: "en"
|
|
186
|
+
renderView:
|
|
187
|
+
- type: div
|
|
188
|
+
attributes:
|
|
189
|
+
style:
|
|
190
|
+
display: "grid"
|
|
191
|
+
gridTemplateColumns: "1fr 1fr"
|
|
192
|
+
gap: "1rem"
|
|
193
|
+
marginBottom: "1rem"
|
|
194
|
+
content:
|
|
195
|
+
- type: div
|
|
196
|
+
attributes:
|
|
197
|
+
style:
|
|
198
|
+
padding: "1rem"
|
|
199
|
+
border: "1px solid #ddd"
|
|
200
|
+
borderRadius: "4px"
|
|
201
|
+
backgroundColor: "#f5f5f5"
|
|
202
|
+
content:
|
|
203
|
+
- type: h5
|
|
204
|
+
content: "Profile Data"
|
|
205
|
+
- type: p
|
|
206
|
+
content: ["Name: ", ~~.profile.name]
|
|
207
|
+
- type: p
|
|
208
|
+
content: ["Age: ", ~~.profile.age]
|
|
209
|
+
- type: div
|
|
210
|
+
attributes:
|
|
211
|
+
style:
|
|
212
|
+
padding: "1rem"
|
|
213
|
+
border: "1px solid #ddd"
|
|
214
|
+
borderRadius: "4px"
|
|
215
|
+
backgroundColor: "#f5f5f5"
|
|
216
|
+
content:
|
|
217
|
+
- type: h5
|
|
218
|
+
content: "Settings Data"
|
|
219
|
+
- type: p
|
|
220
|
+
content: ["Theme: ", ~~.settings.theme]
|
|
221
|
+
- type: p
|
|
222
|
+
content: ["Language: ", ~~.settings.language]
|
|
223
|
+
|
|
224
|
+
- type: ReactiveJsonSubroot
|
|
225
|
+
sharedUpdates: true
|
|
226
|
+
rjOptions:
|
|
227
|
+
dataOverride:
|
|
228
|
+
userProfile: ~~.profile
|
|
229
|
+
userSettings: ~~.settings
|
|
230
|
+
maybeRawAppRjBuild:
|
|
231
|
+
renderView:
|
|
232
|
+
- type: div
|
|
233
|
+
attributes:
|
|
234
|
+
style:
|
|
235
|
+
display: "grid"
|
|
236
|
+
gridTemplateColumns: "1fr 1fr"
|
|
237
|
+
gap: "1rem"
|
|
238
|
+
padding: "1rem"
|
|
239
|
+
border: "2px solid #17a2b8"
|
|
240
|
+
borderRadius: "8px"
|
|
241
|
+
backgroundColor: "#e3f2fd"
|
|
242
|
+
content:
|
|
243
|
+
- type: div
|
|
244
|
+
content:
|
|
245
|
+
- type: h5
|
|
246
|
+
content: "Edit Profile"
|
|
247
|
+
- type: TextField
|
|
248
|
+
label: "Name"
|
|
249
|
+
dataLocation: ~.userProfile.name
|
|
250
|
+
- type: NumberField
|
|
251
|
+
label: "Age"
|
|
252
|
+
dataLocation: ~.userProfile.age
|
|
253
|
+
- type: div
|
|
254
|
+
content:
|
|
255
|
+
- type: h5
|
|
256
|
+
content: "Edit Settings"
|
|
257
|
+
- type: TextField
|
|
258
|
+
label: "Theme"
|
|
259
|
+
dataLocation: ~.userSettings.theme
|
|
260
|
+
- type: TextField
|
|
261
|
+
label: "Language"
|
|
262
|
+
dataLocation: ~.userSettings.language
|
|
263
|
+
|
|
264
|
+
- type: RjBuildDescriber
|
|
265
|
+
title: Example with Array References
|
|
266
|
+
description: This example demonstrates how to work with arrays in `dataOverride` where each array item is mapped to different parts of the parent data. The subroot can edit individual array items and changes will be propagated back to their respective locations in the parent array.
|
|
267
|
+
toDescribe:
|
|
268
|
+
data:
|
|
269
|
+
items:
|
|
270
|
+
- title: "Task 1"
|
|
271
|
+
completed: false
|
|
272
|
+
- title: "Task 2"
|
|
273
|
+
completed: true
|
|
274
|
+
renderView:
|
|
275
|
+
- type: div
|
|
276
|
+
attributes:
|
|
277
|
+
style:
|
|
278
|
+
padding: "1rem"
|
|
279
|
+
border: "1px solid #ddd"
|
|
280
|
+
borderRadius: "4px"
|
|
281
|
+
backgroundColor: "#f9f9f9"
|
|
282
|
+
marginBottom: "1rem"
|
|
283
|
+
content:
|
|
284
|
+
- type: h4
|
|
285
|
+
content: "Parent Items Display"
|
|
286
|
+
- type: p
|
|
287
|
+
content: ["Item 1: ", ~~.items.0.title, " (", ~~.items.0.completed, ")"]
|
|
288
|
+
- type: p
|
|
289
|
+
content: ["Item 2: ", ~~.items.1.title, " (", ~~.items.1.completed, ")"]
|
|
290
|
+
|
|
291
|
+
- type: ReactiveJsonSubroot
|
|
292
|
+
sharedUpdates: true
|
|
293
|
+
rjOptions:
|
|
294
|
+
dataOverride:
|
|
295
|
+
- ~~.items.0
|
|
296
|
+
- ~~.items.1
|
|
297
|
+
maybeRawAppRjBuild:
|
|
298
|
+
renderView:
|
|
299
|
+
- type: div
|
|
300
|
+
attributes:
|
|
301
|
+
style:
|
|
302
|
+
padding: "1rem"
|
|
303
|
+
border: "2px solid #ffc107"
|
|
304
|
+
borderRadius: "8px"
|
|
305
|
+
backgroundColor: "#fff3cd"
|
|
306
|
+
content:
|
|
307
|
+
- type: h4
|
|
308
|
+
content: "Array Items Editor"
|
|
309
|
+
- type: div
|
|
310
|
+
content:
|
|
311
|
+
- type: h5
|
|
312
|
+
content: "First Item"
|
|
313
|
+
- type: TextField
|
|
314
|
+
label: "Title"
|
|
315
|
+
dataLocation: ~.0.title
|
|
316
|
+
- type: CheckBoxField
|
|
317
|
+
label: "Completed"
|
|
318
|
+
dataLocation: ~.0.completed
|
|
319
|
+
- type: div
|
|
320
|
+
content:
|
|
321
|
+
- type: h5
|
|
322
|
+
content: "Second Item"
|
|
323
|
+
- type: TextField
|
|
324
|
+
label: "Title"
|
|
325
|
+
dataLocation: ~.1.title
|
|
326
|
+
- type: CheckBoxField
|
|
327
|
+
label: "Completed"
|
|
328
|
+
dataLocation: ~.1.completed
|
|
329
|
+
|
|
47
330
|
- type: Markdown
|
|
48
331
|
content: |
|
|
332
|
+
## Caveat: Data Loss Risk with sharedUpdates
|
|
333
|
+
|
|
334
|
+
**⚠️ Important Warning**: When using `sharedUpdates`, there is a risk of data loss in specific scenarios.
|
|
335
|
+
|
|
336
|
+
### The Problem
|
|
337
|
+
If the subroot modifies data that is **not** covered by a template reference from the parent's `dataOverride`, and subsequently the parent re-renders the subroot, the local modifications will be **lost**.
|
|
338
|
+
|
|
339
|
+
### When This Happens
|
|
340
|
+
1. **Subroot modifies local data**: The subroot changes a value that doesn't correspond to any template reference in the parent's `dataOverride`.
|
|
341
|
+
2. **Parent re-renders**: This can occur when:
|
|
342
|
+
- The parent updates itself for any reason.
|
|
343
|
+
- A subroot action triggers an upstream update that causes the parent to re-render.
|
|
344
|
+
3. **Data loss**: The parent's `dataOverride` completely overwrites the subroot's data, erasing local modifications.
|
|
345
|
+
|
|
346
|
+
### Best Practices to Avoid Data Loss
|
|
347
|
+
1. **Map all needed data**: Ensure all data fields the subroot might modify are included in the parent's data structure.
|
|
348
|
+
2. **Use complete dataOverride**: Include all necessary data paths in your `dataOverride` mapping.
|
|
349
|
+
3. **Avoid local-only modifications**: Design your data flow so that all user inputs correspond to parent data.
|
|
350
|
+
4. **Consider alternatives**: For truly local data, consider using component state or separate data management instead of `sharedUpdates`.
|
|
351
|
+
|
|
49
352
|
## Limitations
|
|
50
|
-
-
|
|
51
|
-
-
|
|
353
|
+
- **Data loss risk**: Local modifications in subroot may be lost when parent re-renders (see Caveat section above).
|
|
354
|
+
- **Nested references in data**: References within references are not supported.
|
|
355
|
+
- **Circular references**: May cause infinite loops if data structures reference each other.
|
|
356
|
+
- **Isolation by default**: Without `sharedUpdates`, the subroot is completely isolated from the parent.
|
|
357
|
+
- **Backward compatibility**: `sharedUpdates` is disabled by default to maintain existing behavior.
|
|
358
|
+
|
|
359
|
+
- type: Markdown
|
|
360
|
+
content: |
|
|
361
|
+
## Changelog
|
|
362
|
+
|
|
363
|
+
### reactive-json@0.1.0
|
|
364
|
+
- **New**: `sharedUpdates` feature - enables automatic data synchronization between subroot and parent
|
|
365
|
+
- **New**: `dataOverride` property - allows complete data replacement in subroot with support for template references
|
|
366
|
+
- **New**: Automatic analysis of template references in `dataOverride` for shared updates propagation
|
|
@@ -188,7 +188,7 @@ Other specialized contexts are available.
|
|
|
188
188
|
- **PaginationContext**: Used by components that integrate pagination, such as Switch.
|
|
189
189
|
|
|
190
190
|
### Key Functions
|
|
191
|
-
- **evaluateTemplateValue()**: Evaluates template patterns (`~.value`, `~~.value`,
|
|
191
|
+
- **evaluateTemplateValue()**: Evaluates template patterns (`~.value`, `~~.value`, `~>key` for nearest, `~~>key` for global)
|
|
192
192
|
- **useEvaluatedAttributes()**: Hook to evaluate dynamic attributes
|
|
193
193
|
- **propsDataLocationToPathAndValue()**: Form-specific data location handling
|
|
194
194
|
|
|
@@ -351,7 +351,8 @@ data:
|
|
|
351
351
|
renderView:
|
|
352
352
|
- content: ~~.global_value # From root data
|
|
353
353
|
- content: ~.nested_value # From current template
|
|
354
|
-
- content:
|
|
354
|
+
- content: ~>parent_key.nested_value # Get from nearest parent_key
|
|
355
|
+
- content: ~~>parent_key.nested_value # Get from top-level parent_key
|
|
355
356
|
```
|
|
356
357
|
|
|
357
358
|
### Common RjBuild Patterns
|
|
@@ -130,7 +130,7 @@ export const MyWrapper = ({ props, path, currentData, datafield }) => {
|
|
|
130
130
|
## Key APIs and Utilities
|
|
131
131
|
|
|
132
132
|
### Template Evaluation
|
|
133
|
-
- **evaluateTemplateValue()**: Evaluates template patterns like `~.value`, `~~.value`,
|
|
133
|
+
- **evaluateTemplateValue()**: Evaluates template patterns like `~.value`, `~~.value`, `~>key` (nearest), `~~>key` (global)
|
|
134
134
|
- **evaluateTemplateValueCollection()**: Evaluates collections and arrays with template patterns, supports multiple elements
|
|
135
135
|
- **useEvaluatedAttributes()**: Hook to evaluate dynamic attributes object
|
|
136
136
|
|
|
@@ -144,7 +144,7 @@ renderView:
|
|
|
144
144
|
## Key APIs and Utilities
|
|
145
145
|
|
|
146
146
|
### Template Evaluation
|
|
147
|
-
- **evaluateTemplateValue()**: Evaluates template patterns like `~.value`, `~~.value`,
|
|
147
|
+
- **evaluateTemplateValue()**: Evaluates template patterns like `~.value`, `~~.value`, `~>key` (nearest), `~~>key` (global)
|
|
148
148
|
- **evaluateTemplateValueCollection()**: Evaluates collections and arrays with template patterns, supports multiple elements
|
|
149
149
|
- **useEvaluatedAttributes()**: Hook to evaluate dynamic attributes object
|
|
150
150
|
|
|
@@ -30,13 +30,12 @@ data: # Defines the data to be used (optional)
|
|
|
30
30
|
|
|
31
31
|
## Key Concepts
|
|
32
32
|
|
|
33
|
-
###
|
|
33
|
+
### Template System
|
|
34
34
|
|
|
35
|
-
Reactive-JSON
|
|
35
|
+
In Reactive-JSON, you will often find those notations to access data:
|
|
36
36
|
|
|
37
|
-
- `~.` : Local context (relative to current template)
|
|
37
|
+
- `~.` : Local context (relative to current template)
|
|
38
38
|
- `~~.` : Global context (access to global data)
|
|
39
|
-
- `~>field` : Access to a specific parent context
|
|
40
39
|
|
|
41
40
|
Example:
|
|
42
41
|
```yaml
|
|
@@ -48,9 +47,15 @@ templates:
|
|
|
48
47
|
content: ["Name: ", ~.name] # Local access to user data
|
|
49
48
|
- type: div
|
|
50
49
|
content: ["Admin: ", ~~.isAdmin] # Global access to isAdmin
|
|
50
|
+
|
|
51
|
+
data:
|
|
52
|
+
name: "John"
|
|
53
|
+
isAdmin: true
|
|
51
54
|
```
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
> 💡 **Advanced navigation:** For complex hierarchical data access, see the [Template System documentation](/docs/template) which covers `~>key` and `~~>key` notations.
|
|
57
|
+
|
|
58
|
+
### Basic Elements
|
|
54
59
|
|
|
55
60
|
Reactive-JSON provides several types of elements:
|
|
56
61
|
|
|
@@ -80,12 +85,15 @@ renderView:
|
|
|
80
85
|
renderView:
|
|
81
86
|
- type: Switch
|
|
82
87
|
content: ~.items
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
singleOption:
|
|
89
|
+
load: itemTemplate
|
|
90
|
+
templates:
|
|
91
|
+
itemTemplate:
|
|
92
|
+
type: div
|
|
93
|
+
content: ~.name
|
|
86
94
|
```
|
|
87
95
|
|
|
88
|
-
###
|
|
96
|
+
### Actions and Reactions
|
|
89
97
|
|
|
90
98
|
#### Actions
|
|
91
99
|
Actions modify element behavior:
|
|
@@ -33,12 +33,13 @@ renderView:
|
|
|
33
33
|
content: |
|
|
34
34
|
## Key Concepts
|
|
35
35
|
|
|
36
|
-
###
|
|
36
|
+
### Template System
|
|
37
37
|
|
|
38
|
-
Reactive-JSON
|
|
38
|
+
In Reactive-JSON, you will often find those notations to access data:
|
|
39
39
|
- `~.` : Local context (relative to current template)
|
|
40
40
|
- `~~.` : Global context (access to global data)
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
> 💡 **Advanced navigation:** For complex hierarchical data access, see the [Template System documentation](/docs/template) which covers `~>key` and `~~>key` notations.
|
|
42
43
|
|
|
43
44
|
- type: RjBuildDescriber
|
|
44
45
|
title: "Template System Example"
|
|
@@ -62,7 +63,7 @@ renderView:
|
|
|
62
63
|
|
|
63
64
|
- type: Markdown
|
|
64
65
|
content: |
|
|
65
|
-
###
|
|
66
|
+
### Basic Elements
|
|
66
67
|
|
|
67
68
|
Reactive-JSON provides several types of elements:
|
|
68
69
|
|
|
@@ -114,9 +115,12 @@ renderView:
|
|
|
114
115
|
renderView:
|
|
115
116
|
- type: Switch
|
|
116
117
|
content: ~.items
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
singleOption:
|
|
119
|
+
load: itemTemplate
|
|
120
|
+
templates:
|
|
121
|
+
itemTemplate:
|
|
122
|
+
type: div
|
|
123
|
+
content: ~.name
|
|
120
124
|
data:
|
|
121
125
|
items:
|
|
122
126
|
- name: "Item 1"
|
|
@@ -124,7 +128,7 @@ renderView:
|
|
|
124
128
|
|
|
125
129
|
- type: Markdown
|
|
126
130
|
content: |
|
|
127
|
-
###
|
|
131
|
+
### Actions and Reactions
|
|
128
132
|
|
|
129
133
|
#### Actions
|
|
130
134
|
Actions modify element behavior.
|
|
@@ -873,7 +873,6 @@ renderView:
|
|
|
873
873
|
**Need help?**
|
|
874
874
|
|
|
875
875
|
- Check the [Troubleshooting Guide](/docs/troubleshooting/)
|
|
876
|
-
- Join our [Community Discord](https://discord.gg/reactive-json)
|
|
877
876
|
- Open an issue on [GitHub](https://github.com/Ealab-collab/reactive-json/issues)
|
|
878
877
|
|
|
879
878
|
templates:
|
|
@@ -6,41 +6,134 @@ The template system in reactive-json efficiently manages data contexts and their
|
|
|
6
6
|
|
|
7
7
|
## Context Notations
|
|
8
8
|
|
|
9
|
-
There are
|
|
9
|
+
There are four main notations for accessing data:
|
|
10
10
|
|
|
11
11
|
- `~.` : Local context (relative to current template)
|
|
12
12
|
- `~~.` : Global context (access to global data)
|
|
13
|
-
- `~>
|
|
13
|
+
- `~>key` : Finds the nearest "key" by going up the hierarchy (useful when multiple keys exist)
|
|
14
|
+
- `~~>key` : Finds the top-level "key" from root (useful for global settings)
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
Each notation is explained with examples below.
|
|
17
|
+
|
|
18
|
+
#### Local Context (`~.`)
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
renderView:
|
|
22
|
+
- type: div
|
|
23
|
+
content: ["Hello ", ~.username] # Accesses username from current context
|
|
24
|
+
|
|
25
|
+
data:
|
|
26
|
+
username: "John"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
#### Global Context (`~~.`)
|
|
16
30
|
|
|
17
31
|
```yaml
|
|
18
32
|
templates:
|
|
19
|
-
|
|
20
|
-
type:
|
|
21
|
-
content: ~~.users
|
|
22
|
-
template:
|
|
23
|
-
type: div
|
|
33
|
+
userCard:
|
|
34
|
+
- type: div
|
|
24
35
|
content:
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
- "Admin: "
|
|
37
|
+
- type: LabelFromValue
|
|
38
|
+
dataLocation: ~~.isAdmin # Accesses isAdmin from global data
|
|
39
|
+
options:
|
|
40
|
+
- label: "Yes"
|
|
41
|
+
value: true
|
|
42
|
+
- label: "No"
|
|
43
|
+
value: false
|
|
44
|
+
|
|
45
|
+
renderView:
|
|
46
|
+
- load: userCard
|
|
31
47
|
|
|
32
48
|
data:
|
|
33
|
-
users:
|
|
34
|
-
- name: "John"
|
|
35
49
|
isAdmin: true
|
|
36
|
-
userList:
|
|
37
|
-
title: "User List"
|
|
38
50
|
```
|
|
39
51
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
#### Nearest Key (`~>key`)
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
templates:
|
|
56
|
+
themeDisplay:
|
|
57
|
+
type: div
|
|
58
|
+
content: ["Theme: ", ~>config.theme] # Gets theme from nearest config
|
|
59
|
+
|
|
60
|
+
renderView:
|
|
61
|
+
- type: Switch
|
|
62
|
+
content: ~~.config.userSection.config.items
|
|
63
|
+
singleOption:
|
|
64
|
+
load: themeDisplay
|
|
65
|
+
|
|
66
|
+
data:
|
|
67
|
+
config:
|
|
68
|
+
theme: "dark"
|
|
69
|
+
userSection:
|
|
70
|
+
config:
|
|
71
|
+
theme: "light" # This will be found (nearest)
|
|
72
|
+
items:
|
|
73
|
+
- name: "Item 1" # themeDisplay template runs here
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### Top-level Key (`~~>key`)
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
templates:
|
|
80
|
+
themeDisplay:
|
|
81
|
+
type: div
|
|
82
|
+
content: ["Theme: ", ~~>config.theme] # Gets theme from top-level config
|
|
83
|
+
|
|
84
|
+
renderView:
|
|
85
|
+
- type: Switch
|
|
86
|
+
content: ~~.config.userSection.config.items
|
|
87
|
+
singleOption:
|
|
88
|
+
load: themeDisplay
|
|
89
|
+
|
|
90
|
+
data:
|
|
91
|
+
config:
|
|
92
|
+
theme: "dark" # This will be found (top-level)
|
|
93
|
+
userSection:
|
|
94
|
+
config:
|
|
95
|
+
theme: "light"
|
|
96
|
+
items:
|
|
97
|
+
- name: "Item 1" # themeDisplay template runs here
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Complete Practical Example
|
|
101
|
+
|
|
102
|
+
Here's a complete working example that demonstrates all four syntaxes in action:
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
data:
|
|
106
|
+
global_value: "Hello"
|
|
107
|
+
config:
|
|
108
|
+
theme: "dark"
|
|
109
|
+
userSection:
|
|
110
|
+
title: "User List"
|
|
111
|
+
config:
|
|
112
|
+
theme: "light"
|
|
113
|
+
level1:
|
|
114
|
+
items:
|
|
115
|
+
- name: "Item 1"
|
|
116
|
+
# userList template instances run here at: data.config.userSection.level1.items
|
|
117
|
+
|
|
118
|
+
templates:
|
|
119
|
+
userList:
|
|
120
|
+
type: div
|
|
121
|
+
content:
|
|
122
|
+
- type: div
|
|
123
|
+
content: ["Global: ", ~~.global_value] # From root data
|
|
124
|
+
- type: div
|
|
125
|
+
content: ["Local: ", ~.name] # From current template
|
|
126
|
+
- type: div
|
|
127
|
+
content: ["Theme (nearest): ", ~>config.theme] # Get from nearest config → "light"
|
|
128
|
+
- type: div
|
|
129
|
+
content: ["Theme (global): ", ~~>config.theme] # Get from top-level config → "dark"
|
|
130
|
+
|
|
131
|
+
renderView:
|
|
132
|
+
- type: Switch
|
|
133
|
+
content: ~~.config.userSection.level1.items
|
|
134
|
+
singleOption:
|
|
135
|
+
load: userList
|
|
136
|
+
```
|
|
44
137
|
|
|
45
138
|
## Containerization Principle
|
|
46
139
|
|
|
@@ -85,10 +178,12 @@ data:
|
|
|
85
178
|
2. Actions and reactions respect the context where they are defined
|
|
86
179
|
3. Containerization allows isolating modifications until validation
|
|
87
180
|
4. `~~.` allows "escaping" the container to access global data
|
|
88
|
-
5. `~>
|
|
181
|
+
5. `~>key` finds the nearest "key" by going up step by step (useful for local overrides)
|
|
182
|
+
6. `~~>key` finds the top-level "key" from root (useful for global settings)
|
|
89
183
|
|
|
90
184
|
## Best Practices
|
|
91
185
|
|
|
92
186
|
1. **Context Coherence**: Ensure components that need to share data are in the same context
|
|
93
187
|
2. **Global Access**: Use `~~.` for data that needs to be shared between different templates
|
|
94
|
-
3. **Hierarchical Navigation**: Use `~>
|
|
188
|
+
3. **Hierarchical Navigation**: Use `~>key` to find nearest occurrence or `~~>key` to find global setting
|
|
189
|
+
4. **Local vs Global**: `~>` prioritizes local overrides, `~~>` prioritizes global settings
|
|
@@ -7,46 +7,117 @@ renderView:
|
|
|
7
7
|
|
|
8
8
|
The template system in reactive-json efficiently manages data contexts and their access. Understanding how templates "containerize" data is essential for properly using components, actions, and reactions.
|
|
9
9
|
|
|
10
|
+
- type: Markdown
|
|
11
|
+
content: |
|
|
12
|
+
There are four main notations for accessing data:
|
|
13
|
+
|
|
14
|
+
- `~.` : Local context (relative to current template)
|
|
15
|
+
- `~~.` : Global context (access to global data)
|
|
16
|
+
- `~>key` : Finds the nearest "key" by going up the hierarchy (useful when multiple keys exist)
|
|
17
|
+
- `~~>key` : Finds the top-level "key" from root (useful for global settings)
|
|
18
|
+
|
|
19
|
+
Each notation is explained with examples below.
|
|
20
|
+
|
|
21
|
+
- type: RjBuildDescriber
|
|
22
|
+
title: "Local Context (`~.`)"
|
|
23
|
+
description:
|
|
24
|
+
- type: Markdown
|
|
25
|
+
content: |
|
|
26
|
+
Accesses data from the current template context.
|
|
27
|
+
|
|
28
|
+
toDescribe:
|
|
29
|
+
renderView:
|
|
30
|
+
- type: div
|
|
31
|
+
content: ["Hello ", ~.username] # Accesses username from current context
|
|
32
|
+
|
|
33
|
+
data:
|
|
34
|
+
username: "John"
|
|
35
|
+
|
|
10
36
|
- type: RjBuildDescriber
|
|
11
|
-
title: "Context
|
|
37
|
+
title: "Global Context (`~~.`)"
|
|
12
38
|
description:
|
|
13
39
|
- type: Markdown
|
|
14
40
|
content: |
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- `~.` : Local context (relative to current template)
|
|
18
|
-
- `~~.` : Global context (access to global data)
|
|
19
|
-
- `~>field` : Access to a specific parent context by climbing up to a given key
|
|
41
|
+
Accesses data from the global (root) data, regardless of current template context.
|
|
20
42
|
|
|
21
43
|
toDescribe:
|
|
22
44
|
templates:
|
|
23
|
-
|
|
24
|
-
type:
|
|
25
|
-
content: ~~.users
|
|
26
|
-
template:
|
|
27
|
-
type: div
|
|
45
|
+
userCard:
|
|
46
|
+
- type: div
|
|
28
47
|
content:
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
48
|
+
- "Admin: "
|
|
49
|
+
- type: LabelFromValue
|
|
50
|
+
dataLocation: ~~.isAdmin # Accesses isAdmin from global data
|
|
51
|
+
options:
|
|
52
|
+
- label: "Yes"
|
|
53
|
+
value: true
|
|
54
|
+
- label: "No"
|
|
55
|
+
value: false
|
|
56
|
+
|
|
57
|
+
renderView:
|
|
58
|
+
- load: userCard
|
|
35
59
|
|
|
36
60
|
data:
|
|
37
|
-
users:
|
|
38
|
-
- name: "John"
|
|
39
61
|
isAdmin: true
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
|
|
63
|
+
- type: RjBuildDescriber
|
|
64
|
+
title: "Nearest Key (`~>key`)"
|
|
65
|
+
description:
|
|
66
|
+
- type: Markdown
|
|
67
|
+
content: |
|
|
68
|
+
Searches for "key" by going up the hierarchy, finds the nearest occurrence.
|
|
69
|
+
|
|
70
|
+
toDescribe:
|
|
71
|
+
templates:
|
|
72
|
+
themeDisplay:
|
|
73
|
+
type: div
|
|
74
|
+
content: ["Theme: ", ~>config.theme] # Gets theme from nearest config
|
|
75
|
+
|
|
76
|
+
renderView:
|
|
77
|
+
- type: Switch
|
|
78
|
+
content: ~~.config.userSection.config.items
|
|
79
|
+
singleOption:
|
|
80
|
+
load: themeDisplay
|
|
81
|
+
|
|
82
|
+
data:
|
|
83
|
+
config:
|
|
84
|
+
theme: "dark"
|
|
85
|
+
userSection:
|
|
86
|
+
config:
|
|
87
|
+
theme: "light" # This will be found (nearest)
|
|
88
|
+
items:
|
|
89
|
+
- name: "Item 1" # themeDisplay template runs here
|
|
90
|
+
|
|
91
|
+
- type: RjBuildDescriber
|
|
92
|
+
title: "Top-level Key (`~~>key`)"
|
|
93
|
+
description:
|
|
94
|
+
- type: Markdown
|
|
95
|
+
content: |
|
|
96
|
+
Searches for "key" starting from root, finds the top-level occurrence.
|
|
97
|
+
|
|
98
|
+
toDescribe:
|
|
99
|
+
templates:
|
|
100
|
+
themeDisplay:
|
|
101
|
+
type: div
|
|
102
|
+
content: ["Theme: ", ~~>config.theme] # Gets theme from top-level config
|
|
103
|
+
|
|
104
|
+
renderView:
|
|
105
|
+
- type: Switch
|
|
106
|
+
content: ~~.config.userSection.config.items
|
|
107
|
+
singleOption:
|
|
108
|
+
load: themeDisplay
|
|
109
|
+
|
|
110
|
+
data:
|
|
111
|
+
config:
|
|
112
|
+
theme: "dark" # This will be found (top-level)
|
|
113
|
+
userSection:
|
|
114
|
+
config:
|
|
115
|
+
theme: "light"
|
|
116
|
+
items:
|
|
117
|
+
- name: "Item 1" # themeDisplay template runs here
|
|
42
118
|
|
|
43
119
|
- type: Markdown
|
|
44
120
|
content: |
|
|
45
|
-
In this example:
|
|
46
|
-
- `~.name` accesses the `name` property from the local context (current user)
|
|
47
|
-
- `~~.isAdmin` accesses the `isAdmin` property from the global context
|
|
48
|
-
- `~>userList.title` climbs up to the "userList" template and accesses its `title` property
|
|
49
|
-
|
|
50
121
|
## Containerization Principle
|
|
51
122
|
|
|
52
123
|
Templates create context "containers". This means each template defines its own local data space.
|
|
@@ -96,13 +167,55 @@ renderView:
|
|
|
96
167
|
2. Actions and reactions respect the context where they are defined
|
|
97
168
|
3. Containerization allows isolating modifications until validation
|
|
98
169
|
4. `~~.` allows "escaping" the container to access global data
|
|
99
|
-
5. `~>
|
|
170
|
+
5. `~>key` finds the nearest "key" by going up step by step (useful for local overrides)
|
|
171
|
+
6. `~~>key` finds the top-level "key" from root (useful for global settings)
|
|
100
172
|
|
|
101
173
|
## Best Practices
|
|
102
174
|
|
|
103
175
|
1. **Context Coherence**: Ensure components that need to share data are in the same context
|
|
104
176
|
2. **Global Access**: Use `~~.` for data that needs to be shared between different templates
|
|
105
|
-
3. **Hierarchical Navigation**: Use `~>
|
|
177
|
+
3. **Hierarchical Navigation**: Use `~>key` to find nearest occurrence or `~~>key` to find global setting
|
|
178
|
+
4. **Local vs Global**: `~>` prioritizes local overrides, `~~>` prioritizes global settings
|
|
179
|
+
|
|
180
|
+
- type: RjBuildDescriber
|
|
181
|
+
title: "Complete Practical Example"
|
|
182
|
+
description:
|
|
183
|
+
- type: Markdown
|
|
184
|
+
content: |
|
|
185
|
+
Here's a complete working example that demonstrates all four syntaxes in action with a functional renderView.
|
|
186
|
+
|
|
187
|
+
toDescribe:
|
|
188
|
+
data:
|
|
189
|
+
global_value: "Hello"
|
|
190
|
+
config:
|
|
191
|
+
theme: "dark"
|
|
192
|
+
userSection:
|
|
193
|
+
title: "User List"
|
|
194
|
+
config:
|
|
195
|
+
theme: "light"
|
|
196
|
+
level1:
|
|
197
|
+
items:
|
|
198
|
+
- name: "Item 1"
|
|
199
|
+
# userList template instances run here at: data.config.userSection.level1.items
|
|
200
|
+
|
|
201
|
+
templates:
|
|
202
|
+
userList:
|
|
203
|
+
type: div
|
|
204
|
+
content:
|
|
205
|
+
- type: div
|
|
206
|
+
content: ["Global: ", ~~.global_value] # From root data
|
|
207
|
+
- type: div
|
|
208
|
+
content: ["Local: ", ~.name] # From current template
|
|
209
|
+
- type: div
|
|
210
|
+
content: ["Theme (nearest): ", ~>config.theme] # Get from nearest config → "light"
|
|
211
|
+
- type: div
|
|
212
|
+
content: ["Theme (global): ", ~~>config.theme] # Get from top-level config → "dark"
|
|
213
|
+
|
|
214
|
+
renderView:
|
|
215
|
+
- type: Switch
|
|
216
|
+
content: ~~.config.userSection.level1.items
|
|
217
|
+
singleOption:
|
|
218
|
+
load: userList
|
|
106
219
|
|
|
107
220
|
templates:
|
|
108
221
|
|