@ea-lab/reactive-json-docs 1.4.0 → 2.0.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ea-lab/reactive-json-docs",
3
- "version": "1.4.0",
3
+ "version": "2.0.0",
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": "^1.3.0",
29
+ "@ea-lab/reactive-json": "^1.2.0",
30
30
  "@ea-lab/reactive-json-chartjs": "^1.0.0",
31
31
  "@npmcli/fs": "^4.0.0",
32
32
  "@reduxjs/toolkit": "^2.6.1",
@@ -8,73 +8,42 @@ Dynamically sets or modifies the value of an HTML attribute before rendering. Th
8
8
 
9
9
  ```yaml
10
10
  attributeTransforms:
11
- # Add CSS class (string mode)
11
+ # Add CSS class
12
12
  - what: setAttributeValue
13
13
  name: "class"
14
14
  value: "active"
15
15
 
16
- # Replace attribute value (string mode)
16
+ # Replace attribute value
17
17
  - what: setAttributeValue
18
18
  name: "data-status"
19
19
  mode: "replace"
20
20
  value: ~.currentStatus
21
-
22
- # Merge style object (object mode)
23
- - what: setAttributeValue
24
- name: "style"
25
- value:
26
- borderColor: "#3b82f6"
27
- backgroundColor: "#ffffff"
28
21
  ```
29
22
 
30
23
  ## Properties
31
24
 
32
25
  - **name** *(string, required)*: The name of the attribute to modify.
33
26
  - **mode** *(string, optional)*: The modification mode. Default: `"append"`.
34
- - `"append"`: Adds the value to the existing attribute value (space-separated for strings, merges properties for objects).
27
+ - `"append"`: Adds the value to the existing attribute value (space-separated).
35
28
  - `"replace"`: Completely replaces the existing attribute value.
36
- - **value** *(string | object, required)*: The value to set or append. Supports template evaluation (e.g., `~.dynamicValue`, `~~.globalValue`).
37
- - **String mode**: When `value` is a string, operates in string mode for simple attributes like `class`, `data-*`, etc.
38
- - **Object mode**: When `value` is an object, operates in object mode for complex attributes like `style`. In append mode, merges properties property by property.
39
- - **preventDuplicateValues** *(boolean, optional)*: When `true` (default), prevents duplicate values when using append mode (applies to string mode and string properties in object mode).
40
- - **separator** *(string, optional)*: The separator used between values in string mode. Default: `" "` (space).
29
+ - **value** *(string, required)*: The value to set or append. Supports template evaluation (e.g., `~.dynamicValue`, `~~.globalValue`). Automatically converted to string if not already. Special characters are handled safely.
30
+ - **preventDuplicateValues** *(boolean, optional)*: When `true` (default), prevents duplicate values when using append mode.
31
+ - **separator** *(string, optional)*: The separator used between values. Default: `" "` (space).
41
32
 
42
33
  ## Behavior
43
34
 
44
- The transformer operates in two distinct modes based on the `value` type:
45
-
46
- ### String Mode (when `value` is a string)
47
-
48
35
  - **Append mode**: Adds the new value to the existing attribute, separated by the specified separator.
49
36
  - **Replace mode**: Completely overwrites the existing attribute value.
50
37
  - **Duplicate prevention**: In append mode, prevents adding duplicate values when enabled.
51
38
 
52
- ### Object Mode (when `value` is an object)
53
-
54
- - **Replace mode**: Completely replaces the entire object attribute.
55
- - **Append mode**: Merges properties property by property:
56
- - Starts from the current object attribute
57
- - For each property in `value`, applies the same logic as string mode:
58
- - If both current and new values are strings: appends them (respecting `preventDuplicateValues`)
59
- - Otherwise: replaces the property with the new value (new value has precedence)
60
- - Handles nested objects recursively
61
- - Works on a copy to avoid mutation issues
62
-
63
- ### Undefined Values
64
-
65
- - **Append mode**: `undefined` values are ignored, keeping the current attribute unchanged.
66
- - **Replace mode**: `undefined` is assigned to the attribute.
67
-
68
39
  ## Common Use Cases
69
40
 
70
- - **Dynamic CSS classes**: Adding/removing CSS classes based on state (string mode).
71
- - **Data attributes**: Setting data-* attributes for JavaScript integration (string mode).
72
- - **ARIA attributes**: Dynamically updating accessibility attributes (string mode).
73
- - **Style attributes**: Modifying inline styles conditionally (object mode). Merge style properties without losing existing ones.
74
-
75
- ## Examples
41
+ - **Dynamic CSS classes**: Adding/removing CSS classes based on state.
42
+ - **Data attributes**: Setting data-* attributes for JavaScript integration.
43
+ - **ARIA attributes**: Dynamically updating accessibility attributes.
44
+ - **Style attributes**: Modifying inline styles conditionally.
76
45
 
77
- ### String Mode Example
46
+ ## Example
78
47
 
79
48
  ```yaml
80
49
  renderView:
@@ -122,73 +91,11 @@ data:
122
91
  input_data: ""
123
92
  ```
124
93
 
125
- ### Object Mode Example (Style Merging)
126
-
127
- ```yaml
128
- renderView:
129
- - type: div
130
- attributes:
131
- style:
132
- padding: "10px"
133
- border: "2px solid #007bff"
134
- borderRadius: "4px"
135
- attributeTransforms:
136
- # Merge additional style properties without losing existing ones
137
- - what: setAttributeValue
138
- name: "style"
139
- value:
140
- borderColor: "#3b82f6"
141
- backgroundColor: "#f0f0f0"
142
- when: ~.isHighlighted
143
- is: true
144
- # Result when isHighlighted is true:
145
- # style: {
146
- # padding: "10px",
147
- # border: "2px solid #007bff",
148
- # borderRadius: "4px",
149
- # borderColor: "#3b82f6",
150
- # backgroundColor: "#f0f0f0"
151
- # }
152
-
153
- data:
154
- isHighlighted: false
155
- ```
156
-
157
- ### Object Mode Replace Example
158
-
159
- ```yaml
160
- renderView:
161
- - type: div
162
- attributes:
163
- style:
164
- padding: "10px"
165
- border: "2px solid #007bff"
166
- attributeTransforms:
167
- # Completely replace the style object
168
- - what: setAttributeValue
169
- name: "style"
170
- mode: "replace"
171
- value:
172
- backgroundColor: "#ffffff"
173
- color: "#000000"
174
- # Result:
175
- # style: {
176
- # backgroundColor: "#ffffff",
177
- # color: "#000000"
178
- # }
179
- # (original padding and border are lost)
180
- ```
181
-
182
94
  ## Notes
183
95
 
184
96
  - **Pre-render execution**: This transformer modifies attributes before the component renders, ensuring child components receive the transformed attributes.
185
- - **Mode detection**: The transformer automatically detects whether to use string mode or object mode based on the `value` type after template evaluation.
186
- - **Append mode behavior**:
187
- - **String mode**: Respects existing attribute values, adding new values separated by the specified separator.
188
- - **Object mode**: Merges properties property by property, applying string append logic where both values are strings, otherwise replacing with the new value.
189
- - **Replace mode**: Use when you need complete control over the attribute value. In object mode, completely replaces the entire object.
190
- - **Duplicate prevention**: Only applies to append mode, and works for string values in both string mode and object mode.
191
- - **Object merging**: In object mode append, nested objects are merged recursively. Properties that don't match the expected format for append are replaced (new value has precedence).
97
+ - **Append mode behavior**: Respects existing attribute values when using append mode.
98
+ - **Replace mode**: Use when you need complete control over the attribute value.
99
+ - **Duplicate prevention**: Only applies to append mode.
192
100
  - **Template evaluation**: The value property supports full template evaluation including `~.localData`, `~~.globalData`, `~>nearestKey`, and `~~>globalKey` patterns.
193
101
  - **Conditional execution**: Supports the same condition system as actions (`when`, `is`, `isEmpty`, `isNotEmpty`, etc.).
194
- - **Undefined handling**: `undefined` values are ignored in append mode but assigned in replace mode.
@@ -12,23 +12,16 @@ renderView:
12
12
  - type: TabbedSerializer
13
13
  yamlSerializedContent: |
14
14
  attributeTransforms:
15
- # Add CSS class (string mode)
15
+ # Add CSS class
16
16
  - what: setAttributeValue
17
17
  name: "class"
18
18
  value: "active"
19
19
 
20
- # Replace attribute value (string mode)
20
+ # Replace attribute value
21
21
  - what: setAttributeValue
22
22
  name: "data-status"
23
23
  mode: "replace"
24
24
  value: ~.currentStatus
25
-
26
- # Merge style object (object mode)
27
- - what: setAttributeValue
28
- name: "style"
29
- value:
30
- borderColor: "#3b82f6"
31
- backgroundColor: "#ffffff"
32
25
 
33
26
  - type: Markdown
34
27
  content: |
@@ -51,14 +44,8 @@ renderView:
51
44
  - `"replace"`: Completely replaces the existing attribute value
52
45
  - term:
53
46
  code: value
54
- after: "(string | object, required)"
55
- details:
56
- type: Markdown
57
- content: |
58
- The value to set or append. Supports template evaluation (e.g., `~.dynamicValue`, `~~.globalValue`).
59
-
60
- - **String mode**: When `value` is a string, operates in string mode for simple attributes like `class`, `data-*`, etc.
61
- - **Object mode**: When `value` is an object, operates in object mode for complex attributes like `style`. In append mode, merges properties property by property.
47
+ after: "(string, required)"
48
+ details: The value to set or append. Supports template evaluation (e.g., `~.dynamicValue`, `~~.globalValue`). Automatically converted to string if not already. Special characters are handled safely.
62
49
  - term:
63
50
  code: preventDuplicateValues
64
51
  after: "(boolean, optional)"
@@ -78,36 +65,16 @@ renderView:
78
65
 
79
66
  ## Behavior
80
67
 
81
- The transformer operates in two distinct modes based on the `value` type:
82
-
83
- ### String Mode (when `value` is a string)
84
-
85
68
  - **Append mode**: Adds the new value to the existing attribute, separated by the specified separator.
86
69
  - **Replace mode**: Completely overwrites the existing attribute value.
87
70
  - **Duplicate prevention**: In append mode, prevents adding duplicate values when enabled.
88
71
 
89
- ### Object Mode (when `value` is an object)
90
-
91
- - **Replace mode**: Completely replaces the entire object attribute.
92
- - **Append mode**: Merges properties property by property:
93
- - Starts from the current object attribute
94
- - For each property in `value`, applies the same logic as string mode:
95
- - If both current and new values are strings: appends them (respecting `preventDuplicateValues`)
96
- - Otherwise: replaces the property with the new value (new value has precedence)
97
- - Handles nested objects recursively
98
- - Works on a copy to avoid mutation issues
99
-
100
- ### Undefined Values
101
-
102
- - **Append mode**: `undefined` values are ignored, keeping the current attribute unchanged.
103
- - **Replace mode**: `undefined` is assigned to the attribute.
104
-
105
72
  ## Common Use Cases
106
73
 
107
- - **Dynamic CSS classes**: Adding/removing CSS classes based on state (string mode).
108
- - **Data attributes**: Setting data-* attributes for JavaScript integration (string mode).
109
- - **ARIA attributes**: Dynamically updating accessibility attributes (string mode).
110
- - **Style attributes**: Modifying inline styles conditionally (object mode). Merge style properties without losing existing ones.
74
+ - **Dynamic CSS classes**: Adding/removing CSS classes based on state.
75
+ - **Data attributes**: Setting data-* attributes for JavaScript integration.
76
+ - **ARIA attributes**: Dynamically updating accessibility attributes.
77
+ - **Style attributes**: Modifying inline styles conditionally.
111
78
 
112
79
  - type: RjBuildDescriber
113
80
  title: "SetAttributeValue Action Examples"
@@ -167,90 +134,11 @@ renderView:
167
134
  data:
168
135
  input_data: ""
169
136
 
170
- - type: RjBuildDescriber
171
- title: "Object Mode Example - Style Merging"
172
- description:
173
- - type: Markdown
174
- content: |
175
- This example demonstrates how to use `setAttributeValue` in object mode to merge style properties without losing existing ones.
176
-
177
- **Expected behavior:**
178
- - The div has initial styles (padding, border, borderRadius)
179
- - When `isHighlighted` is true, additional style properties are merged
180
- - The original styles are preserved, and new properties are added
181
- - Try toggling the highlight to see the style merge in action
182
-
183
- toDescribe:
184
- renderView:
185
- - type: div
186
- attributes:
187
- style:
188
- padding: "10px"
189
- border: "2px solid #007bff"
190
- borderRadius: "4px"
191
- attributeTransforms:
192
- # Merge additional style properties without losing existing ones
193
- - what: setAttributeValue
194
- name: "style"
195
- value:
196
- borderColor: "#3b82f6"
197
- backgroundColor: "#f0f0f0"
198
- when: ~.isHighlighted
199
- is: true
200
- content: "Click to toggle highlight"
201
-
202
- - type: button
203
- content: "Toggle Highlight"
204
- actions:
205
- - what: setData
206
- on: click
207
- path: ~.isHighlighted
208
- value: <reactive-json:not>~~.isHighlighted</reactive-json:not>
209
-
210
- data:
211
- isHighlighted: false
212
-
213
- - type: RjBuildDescriber
214
- title: "Object Mode Replace Example"
215
- description:
216
- - type: Markdown
217
- content: |
218
- This example demonstrates how to completely replace a style object using `mode: "replace"`.
219
-
220
- **Expected behavior:**
221
- - The div has initial styles (padding, border)
222
- - When replace mode is used, the entire style object is replaced
223
- - Original styles are lost, only the new styles remain
224
-
225
- toDescribe:
226
- renderView:
227
- - type: div
228
- attributes:
229
- style:
230
- padding: "10px"
231
- border: "2px solid #007bff"
232
- attributeTransforms:
233
- # Completely replace the style object
234
- - what: setAttributeValue
235
- name: "style"
236
- mode: "replace"
237
- value:
238
- backgroundColor: "#ffffff"
239
- color: "#000000"
240
- content: "This div's style was completely replaced"
241
-
242
137
  - type: Markdown
243
138
  content: |
244
139
  ## Notes
245
140
 
246
- - **Pre-render execution**: This transformer modifies attributes before the component renders, ensuring child components receive the transformed attributes.
247
- - **Mode detection**: The transformer automatically detects whether to use string mode or object mode based on the `value` type after template evaluation.
248
- - **Append mode behavior**:
249
- - **String mode**: Respects existing attribute values, adding new values separated by the specified separator.
250
- - **Object mode**: Merges properties property by property, applying string append logic where both values are strings, otherwise replacing with the new value.
251
- - **Replace mode**: Use when you need complete control over the attribute value. In object mode, completely replaces the entire object.
252
- - **Duplicate prevention**: Only applies to append mode, and works for string values in both string mode and object mode.
253
- - **Object merging**: In object mode append, nested objects are merged recursively. Properties that don't match the expected format for append are replaced (new value has precedence).
254
- - **Template evaluation**: The value property supports full template evaluation including `~.localData`, `~~.globalData`, `~>nearestKey`, and `~~>globalKey` patterns.
255
- - **Conditional execution**: Supports the same condition system as actions (`when`, `is`, `isEmpty`, `isNotEmpty`, etc.).
256
- - **Undefined handling**: `undefined` values are ignored in append mode but assigned in replace mode.
141
+ - The action respects existing attribute values when using append mode.
142
+ - Use replace mode when you need complete control over the attribute value.
143
+ - Duplicate prevention only applies to append mode.
144
+ - The value property supports full template evaluation including `~.localData`, `~~.globalData`, `~>nearestKey`, and `~~>globalKey` patterns.
@@ -0,0 +1,252 @@
1
+ # DataSync
2
+
3
+ The `DataSync` component enables automatic synchronization between client-side data and a backend endpoint. It watches a **Syncable Object** in the data tree and pushes changes to a server when triggered, either automatically after a period of inactivity, immediately on change, or manually via an explicit trigger.
4
+
5
+ This component does not render any visible UI. It acts as a background observer.
6
+
7
+ ## The Syncable Object
8
+
9
+ `DataSync` watches a data object that follows a specific structure called a **Syncable Object**. This object contains both the data to synchronize and the configuration needed to reach the backend.
10
+
11
+ ### Structure
12
+
13
+ ```yaml
14
+ mySyncableObject:
15
+ submission_url: "https://api.example.com/items/save"
16
+ item_url: "https://api.example.com/items/123"
17
+ delete_url: "https://api.example.com/items/123"
18
+ data:
19
+ entity_id: 123
20
+ name: "John Doe"
21
+ email: "john@example.com"
22
+ status:
23
+ type: "info"
24
+ message: "Ready"
25
+ ```
26
+
27
+ ### Fields
28
+
29
+ | Field | Type | Required | Description |
30
+ |---|---|---|---|
31
+ | `submission_url` | string | Yes | URL where the object is sent for create/update (POST). This is the only URL used by the `DataSync` component. If `entity_id` is absent from `data`, the backend should treat it as a creation. |
32
+ | `item_url` | string | No | URL to fetch the latest version of the item (GET). **Not used by `DataSync` itself** — provided as metadata for the backend or other components. |
33
+ | `delete_url` | string | No | URL to delete the item (DELETE). **Not used by `DataSync` itself** — provided as metadata for the backend or other components. |
34
+ | `data` | any | Yes | The actual payload to synchronize. Its structure depends on the backend. Only changes to this field trigger synchronization. |
35
+ | `status` | object | No | Feedback message from the last operation. Contains `type` and `message`. |
36
+
37
+ ### The `status` field
38
+
39
+ The `status` field follows a standard structure with two properties:
40
+
41
+ | Property | Type | Description |
42
+ |---|---|---|
43
+ | `type` | string | One of: `success`, `error`, `info`, `warning`. |
44
+ | `message` | string | Human-readable message describing the result. |
45
+
46
+ The `status` field is managed in three ways:
47
+ 1. **By the component**: Set to `{ type: "info", message: "Synchronisation en cours..." }` while a request is in flight.
48
+ 2. **By the backend**: The server response replaces the entire Syncable Object, including the `status` field. The backend can set it to `success`, `error`, or any type with a relevant message.
49
+ 3. **On HTTP failure**: If the request fails (network error, 5xx), the component generates `{ type: "error", message: "..." }` locally.
50
+
51
+ ### Backend contract
52
+
53
+ When `DataSync` sends a request, it POSTs the **entire Syncable Object** (not just `data`) to `submission_url`. The backend must return the same Syncable Object structure in its response, potentially with:
54
+ - Modified `data` (e.g., server-generated fields like `entity_id` or timestamps).
55
+ - An updated `status` field reflecting the result of the operation.
56
+
57
+ The response completely replaces the local Syncable Object.
58
+
59
+ ## Properties
60
+
61
+ | Property | Type | Default | Description |
62
+ |---|---|---|---|
63
+ | `path` | string | (required) | Path to the Syncable Object to watch. Supports template paths (`~~.`, `~.`, `~>`). |
64
+ | `mode` | string | `"onIdle"` | Synchronization mode: `"onIdle"`, `"immediate"`, or `"manual"`. |
65
+ | `idleDelay` | number | `1000` | Milliseconds of inactivity before syncing (only used in `onIdle` mode). |
66
+ | `trigger` | string | - | Path to a boolean value. When set to `true`, triggers an immediate sync and resets to `false`. Works in any mode. In `onIdle` mode, it cancels the pending idle timer. |
67
+ | `maxRetries` | number | `0` | Number of additional retry attempts after a failed sync. `0` means one attempt with no retry. |
68
+ | `retryDelay` | number | `5000` | Milliseconds between retry attempts. |
69
+
70
+ ## Synchronization Modes
71
+
72
+ ### `onIdle` (default)
73
+ Waits for the user to stop modifying data. Each change resets the idle timer. The sync fires only after `idleDelay` milliseconds of inactivity.
74
+
75
+ ```yaml
76
+ - type: DataSync
77
+ path: ~~.userProfile
78
+ mode: onIdle
79
+ idleDelay: 2000
80
+ ```
81
+
82
+ ### `immediate`
83
+ Syncs immediately on every data change. Use with caution -- this can generate a high volume of requests.
84
+
85
+ ```yaml
86
+ - type: DataSync
87
+ path: ~~.settings
88
+ mode: immediate
89
+ ```
90
+
91
+ ### `manual`
92
+ Does not sync on data changes. Waits for the `trigger` path to become `true`.
93
+
94
+ ```yaml
95
+ - type: DataSync
96
+ path: ~~.formData
97
+ mode: manual
98
+ trigger: ~~.saveNow
99
+ ```
100
+
101
+ ## Manual Trigger
102
+
103
+ The `trigger` property works in **any mode**, not just `manual`. When the trigger path is set to `true`:
104
+
105
+ 1. The trigger is immediately reset to `false`.
106
+ 2. Any pending idle timer is cancelled (in `onIdle` mode).
107
+ 3. A sync is performed immediately.
108
+
109
+ This is useful for adding a "Save Now" button alongside auto-save:
110
+
111
+ ```yaml
112
+ - type: button
113
+ content: "Save Now"
114
+ actions:
115
+ - what: setData
116
+ on: click
117
+ path: ~~.saveNow
118
+ value: true
119
+
120
+ - type: DataSync
121
+ path: ~~.userProfile
122
+ mode: onIdle
123
+ idleDelay: 2000
124
+ trigger: ~~.saveNow
125
+ ```
126
+
127
+ ## Error Handling and Retries
128
+
129
+ ### Retry behavior
130
+ - Only **network outages** (browser is offline) and **server errors** (HTTP 5xx) trigger retries.
131
+ - Client errors (4xx) and CORS failures do **not** trigger retries.
132
+ - When the user makes a new data change, the retry counter resets and a fresh sync cycle begins.
133
+
134
+ ### Configuration
135
+ ```yaml
136
+ - type: DataSync
137
+ path: ~~.userProfile
138
+ mode: onIdle
139
+ idleDelay: 1000
140
+ maxRetries: 3
141
+ retryDelay: 10000
142
+ ```
143
+
144
+ ## Change Detection
145
+
146
+ `DataSync` only triggers synchronization when the `data` field of the Syncable Object changes. Changes to `status`, `submission_url`, or other fields are ignored.
147
+
148
+ This prevents feedback loops: when the component updates `status` to "syncing" or when the server response updates `status` to "success", these changes do not trigger a new sync cycle.
149
+
150
+ ## Using with Templates
151
+
152
+ `DataSync` supports `TemplateContext`, so it can be used inside templates to sync individual items in a list:
153
+
154
+ ```yaml
155
+ data:
156
+ items:
157
+ - submission_url: "/api/items/1"
158
+ data: { name: "Item 1" }
159
+ - submission_url: "/api/items/2"
160
+ data: { name: "Item 2" }
161
+
162
+ templates:
163
+ itemRow:
164
+ type: div
165
+ content:
166
+ - type: TextField
167
+ dataLocation: ~.data.name
168
+ - type: DataSync
169
+ path: ~
170
+ mode: onIdle
171
+ idleDelay: 1500
172
+
173
+ renderView:
174
+ - type: Switch
175
+ content: ~~.items
176
+ singleOption:
177
+ load: itemRow
178
+ ```
179
+
180
+ ## Displaying Status
181
+
182
+ You can display the status message from the Syncable Object to provide feedback to the user:
183
+
184
+ ```yaml
185
+ - type: div
186
+ content: ~~.userProfile.status.message
187
+ actions:
188
+ - what: hide
189
+ when: ~~.userProfile.status
190
+ is: undefined
191
+ ```
192
+
193
+ ## Complete Example
194
+
195
+ ```yaml
196
+ data:
197
+ userProfile:
198
+ submission_url: "/api/user/save"
199
+ item_url: "/api/user/123"
200
+ delete_url: "/api/user/123"
201
+ data:
202
+ name: "John Doe"
203
+ email: "john@example.com"
204
+ status:
205
+ type: "info"
206
+ message: "Ready"
207
+ saveNow: false
208
+
209
+ renderView:
210
+ - type: div
211
+ content:
212
+ # Status display
213
+ - type: div
214
+ content: ~~.userProfile.status.message
215
+ actions:
216
+ - what: hide
217
+ when: ~~.userProfile.status
218
+ is: undefined
219
+
220
+ # Form fields
221
+ - type: TextField
222
+ label: "Name"
223
+ dataLocation: ~~.userProfile.data.name
224
+
225
+ - type: TextField
226
+ label: "Email"
227
+ dataLocation: ~~.userProfile.data.email
228
+
229
+ # Manual save button
230
+ - type: button
231
+ content: "Save Now"
232
+ actions:
233
+ - what: setData
234
+ on: click
235
+ path: ~~.saveNow
236
+ value: true
237
+
238
+ # DataSync: auto-saves after 2s of idle, manual trigger available
239
+ - type: DataSync
240
+ path: ~~.userProfile
241
+ mode: onIdle
242
+ idleDelay: 2000
243
+ trigger: ~~.saveNow
244
+ ```
245
+
246
+ ## Limitations
247
+ - Only one sync can be active at a time per `DataSync` instance. Concurrent changes while a sync is in flight are not queued.
248
+ - The entire Syncable Object is sent in the POST body, not just the `data` field.
249
+ - Only POST requests are supported for submission. Custom HTTP methods are not configurable.
250
+ - `item_url` and `delete_url` are part of the Syncable Object structure but are not used by the component itself. They are available for the backend or for other components to use.
251
+ - No built-in support for optimistic updates. The local data is replaced by the server response.
252
+ - CORS errors are not retried (they are indistinguishable from network errors when the browser is online).