@ea-lab/reactive-json-docs 2.2.0 → 2.4.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": "2.2.0",
3
+ "version": "2.4.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": [
@@ -0,0 +1,169 @@
1
+ # AutocompleteField
2
+
3
+ The `AutocompleteField` component provides a search-as-you-type input that fetches suggestions from a remote API as the user types. It supports single and multiple value selection, and customizable dropdown and selected-item templates.
4
+
5
+ ## Basic Syntax
6
+
7
+ ```yaml
8
+ - type: AutocompleteField
9
+ dataLocation: ~~.selectedId
10
+ placeholder: "Search…"
11
+ src:
12
+ - "/api/items"
13
+ - param: "search"
14
+ value: "<reactive-json:autocomplete-field:input>"
15
+ - param: "limit"
16
+ value: "10"
17
+ ```
18
+
19
+ ## Properties
20
+
21
+ - `dataLocation` (string, required): Path where the selected value (or array of values in multiple mode) is stored in the data context.
22
+ - `src` (array, required): URL segments used to build the API endpoint, using the same format as `additionalDataSource.src`. The special token `<reactive-json:autocomplete-field:input>` is replaced by the current search text at request time.
23
+ - `placeholder` (string, optional): Placeholder text for the search input.
24
+ - `minChars` (number, optional): Minimum number of characters required before a search is triggered. Defaults to `2`.
25
+ - `debounce` (number, optional): Delay in milliseconds between the last keystroke and the API request. Defaults to `300`.
26
+ - `multiple` (boolean, optional): Enable multiple selection mode. Selected values are stored as an array. Defaults to `false`.
27
+ - `maxItems` (number, optional): Maximum number of items that can be selected in multiple mode. No limit by default.
28
+ - `clearOnSelect` (boolean, optional): Clear the search input and close the dropdown after an item is selected. Defaults to `true`.
29
+ - `itemTemplate` (rjbuild, optional): Template used to render each item in the dropdown. Has access to item data via `~.` (e.g., `~.label`, `~.value`). Defaults to a `div` displaying `~.label`.
30
+ - `selectedTemplate` (rjbuild, optional): Template used to render the selected item (single mode) or each tag (multiple mode). Has access to item data via `~.`. Defaults to a `span` displaying `~.label`.
31
+ - `defaultFieldValue` (any, optional): Default value used when no data is present at `dataLocation`.
32
+ - `attributes` (object, optional): Attributes applied to the root container `div`. Also receives the CSS class `rj-autocomplete` automatically.
33
+ - `actions` (array, optional): Actions to execute based on component state.
34
+
35
+ ## Backend Response Format
36
+
37
+ The endpoint must return a JSON array of objects. Each object must have at minimum a `value` and a `label` key:
38
+
39
+ ```json
40
+ [
41
+ { "value": 42, "label": "First result" },
42
+ { "value": 7, "label": "Second result" }
43
+ ]
44
+ ```
45
+
46
+ Additional keys can be included and are available in `itemTemplate` / `selectedTemplate` via `~.fieldName`.
47
+
48
+ ## The Input Token
49
+
50
+ The string `<reactive-json:autocomplete-field:input>` is a special token that can be placed anywhere in the `src` segments (as a `value`, `param`, or URL segment). It is replaced at request time with the current text in the search field.
51
+
52
+ ```yaml
53
+ src:
54
+ - "/api/search"
55
+ - param: "q"
56
+ value: "<reactive-json:autocomplete-field:input>"
57
+ ```
58
+
59
+ ## CSS Classes
60
+
61
+ The component uses the following CSS classes for styling:
62
+
63
+ - `.rj-autocomplete` — root container
64
+ - `.rj-autocomplete__input` — the search text input
65
+ - `.rj-autocomplete__dropdown` — the suggestions dropdown
66
+ - `.rj-autocomplete__item` — each suggestion item
67
+ - `.rj-autocomplete__item.is-selected` — a suggestion that is already selected (multiple mode)
68
+ - `.rj-autocomplete__selected` — the selected-item area (single mode)
69
+ - `.rj-autocomplete__clear` — the clear button (single mode)
70
+ - `.rj-autocomplete__tag` — a selected tag (multiple mode)
71
+ - `.rj-autocomplete__tag-remove` — the remove button on a tag
72
+ - `.rj-autocomplete__loading` — the loading indicator
73
+
74
+ ## Examples
75
+
76
+ ### Single value selection
77
+
78
+ Stores a single selected value. Shows a clear button once an item is selected.
79
+
80
+ ```yaml
81
+ renderView:
82
+ - type: AutocompleteField
83
+ dataLocation: ~~.selectedId
84
+ placeholder: "Search…"
85
+ src:
86
+ - "/api/items"
87
+ - param: "search"
88
+ value: "<reactive-json:autocomplete-field:input>"
89
+ - param: "limit"
90
+ value: "10"
91
+
92
+ data:
93
+ selectedId: null
94
+ ```
95
+
96
+ ### Multiple selection with a limit
97
+
98
+ Stores up to 3 values as an array. Each selected item is displayed as a removable tag.
99
+
100
+ ```yaml
101
+ renderView:
102
+ - type: AutocompleteField
103
+ dataLocation: ~~.selectedIds
104
+ multiple: true
105
+ maxItems: 3
106
+ placeholder: "Add items (max 3)…"
107
+ src:
108
+ - "/api/items"
109
+ - param: "search"
110
+ value: "<reactive-json:autocomplete-field:input>"
111
+ - param: "limit"
112
+ value: "10"
113
+ - type: p
114
+ content:
115
+ - "Selected IDs: "
116
+ - type: Join
117
+ content: ~~.selectedIds
118
+
119
+ data:
120
+ selectedIds: []
121
+ ```
122
+
123
+ ### Custom templates
124
+
125
+ Use `itemTemplate` and `selectedTemplate` to render richer content. Both templates have access to all fields returned by the backend via `~.`.
126
+
127
+ ```yaml
128
+ - type: AutocompleteField
129
+ dataLocation: ~~.selectedItem
130
+ placeholder: "Search…"
131
+ src:
132
+ - "/api/items"
133
+ - param: "search"
134
+ value: "<reactive-json:autocomplete-field:input>"
135
+ itemTemplate:
136
+ type: div
137
+ content:
138
+ - type: strong
139
+ content: ~.label
140
+ - " (#"
141
+ - ~.value
142
+ - ")"
143
+ selectedTemplate:
144
+ type: span
145
+ content:
146
+ - ~.label
147
+ - " ✓"
148
+ ```
149
+
150
+ ### Keep search text after selection
151
+
152
+ Set `clearOnSelect: false` to keep the typed text and dropdown open after selecting an item (useful in multiple mode when selecting several items quickly).
153
+
154
+ ```yaml
155
+ - type: AutocompleteField
156
+ dataLocation: ~~.selectedIds
157
+ multiple: true
158
+ clearOnSelect: false
159
+ placeholder: "Search…"
160
+ src: [...]
161
+ ```
162
+
163
+ ## Limitations
164
+
165
+ - Requires an external API endpoint; no built-in static options support.
166
+ - The dropdown only renders while the user is actively typing (results are not re-fetched on re-open without re-typing).
167
+ - In multiple mode, selected items' display data is kept in local React state and may be lost on page reload unless persisted separately.
168
+ - Styling must be provided via external CSS targeting the `.rj-autocomplete*` classes, or via `attributes.style`.
169
+ - No built-in keyboard navigation for the dropdown.
@@ -0,0 +1,225 @@
1
+ renderView:
2
+ - type: Markdown
3
+ content: |
4
+ # AutocompleteField
5
+
6
+ The `AutocompleteField` component provides a search-as-you-type input that fetches suggestions from a remote API as the user types. It supports single and multiple value selection, and customizable dropdown and selected-item templates.
7
+
8
+ - type: Markdown
9
+ content: |
10
+ ## Basic Syntax
11
+
12
+ ```yaml
13
+ - type: AutocompleteField
14
+ dataLocation: ~~.selectedId
15
+ placeholder: "Search…"
16
+ src:
17
+ - "/api/items"
18
+ - param: "search"
19
+ value: "<reactive-json:autocomplete-field:input>"
20
+ - param: "limit"
21
+ value: "10"
22
+ ```
23
+
24
+ ## Properties
25
+
26
+ - type: DefinitionList
27
+ content:
28
+ - term:
29
+ code: dataLocation
30
+ after: "(string, required)"
31
+ details: "Path where the selected value (or array of values in multiple mode) is stored in the data context."
32
+ - term:
33
+ code: src
34
+ after: "(array, required)"
35
+ details:
36
+ type: Markdown
37
+ content: "URL segments used to build the API endpoint. The special token `<reactive-json:autocomplete-field:input>` is replaced by the current search text at request time."
38
+ - term:
39
+ code: placeholder
40
+ after: "(string, optional)"
41
+ details: "Placeholder text for the search input."
42
+ - term:
43
+ code: minChars
44
+ after: "(number, optional, default: 2)"
45
+ details: "Minimum number of characters required before a search is triggered."
46
+ - term:
47
+ code: debounce
48
+ after: "(number, optional, default: 300)"
49
+ details: "Delay in milliseconds between the last keystroke and the API request."
50
+ - term:
51
+ code: multiple
52
+ after: "(boolean, optional, default: false)"
53
+ details: "Enable multiple selection mode. Selected values are stored as an array."
54
+ - term:
55
+ code: maxItems
56
+ after: "(number, optional)"
57
+ details: "Maximum number of items selectable in multiple mode. No limit by default."
58
+ - term:
59
+ code: clearOnSelect
60
+ after: "(boolean, optional, default: true)"
61
+ details: "Clear the search input and close the dropdown after an item is selected."
62
+ - term:
63
+ code: itemTemplate
64
+ after: "(rjbuild, optional)"
65
+ details:
66
+ type: Markdown
67
+ content: "Template rendered for each item in the dropdown. Has access to item data via `~.` (e.g., `~.label`, `~.value`). Defaults to a `div` displaying `~.label`."
68
+ - term:
69
+ code: selectedTemplate
70
+ after: "(rjbuild, optional)"
71
+ details:
72
+ type: Markdown
73
+ content: "Template rendered for the selected item (single mode) or each tag (multiple mode). Has access to item data via `~.`. Defaults to a `span` displaying `~.label`."
74
+ - term:
75
+ code: defaultFieldValue
76
+ after: "(any, optional)"
77
+ details: "Default value used when no data is present at dataLocation."
78
+ - term:
79
+ code: attributes
80
+ after: "(object, optional)"
81
+ details:
82
+ type: Markdown
83
+ content: "Attributes applied to the root container `div`. Also receives the CSS class `rj-autocomplete` automatically."
84
+ - term:
85
+ code: actions
86
+ after: "(array, optional)"
87
+ details: "Actions to execute based on component state."
88
+
89
+ - type: Markdown
90
+ content: |
91
+ ## Backend Response Format
92
+
93
+ The endpoint must return a JSON array of objects. Each object must have at minimum a `value` and a `label` key:
94
+
95
+ ```json
96
+ [
97
+ { "value": 42, "label": "First result" },
98
+ { "value": 7, "label": "Second result" }
99
+ ]
100
+ ```
101
+
102
+ Additional keys can be included and are available in `itemTemplate` / `selectedTemplate` via `~.fieldName`.
103
+
104
+ - type: Markdown
105
+ content: |
106
+ ## The Input Token
107
+
108
+ The string `<reactive-json:autocomplete-field:input>` is a special token that can be placed anywhere in the `src` segments. It is replaced at request time with the current text in the search field.
109
+
110
+ ```yaml
111
+ src:
112
+ - "/api/search"
113
+ - param: "q"
114
+ value: "<reactive-json:autocomplete-field:input>"
115
+ ```
116
+
117
+ - type: Markdown
118
+ content: |
119
+ ## CSS Classes
120
+
121
+ The component uses the following CSS classes for styling:
122
+
123
+ | Class | Element |
124
+ |---|---|
125
+ | `.rj-autocomplete` | Root container |
126
+ | `.rj-autocomplete__input` | The search text input |
127
+ | `.rj-autocomplete__dropdown` | The suggestions dropdown |
128
+ | `.rj-autocomplete__item` | Each suggestion item |
129
+ | `.rj-autocomplete__item.is-selected` | A suggestion already selected (multiple mode) |
130
+ | `.rj-autocomplete__selected` | The selected-item area (single mode) |
131
+ | `.rj-autocomplete__clear` | The clear button (single mode) |
132
+ | `.rj-autocomplete__tag` | A selected tag (multiple mode) |
133
+ | `.rj-autocomplete__tag-remove` | The remove button on a tag |
134
+ | `.rj-autocomplete__loading` | The loading indicator |
135
+
136
+ - type: Markdown
137
+ content: |
138
+ ## Examples
139
+
140
+ > **Note**: The following examples require a live API endpoint. They show the YAML configuration without a live demo.
141
+
142
+ ### Single value selection
143
+
144
+ Stores a single selected value. Shows a clear button once an item is selected.
145
+
146
+ ```yaml
147
+ renderView:
148
+ - type: AutocompleteField
149
+ dataLocation: ~~.selectedId
150
+ placeholder: "Search…"
151
+ src:
152
+ - "/api/items"
153
+ - param: "search"
154
+ value: "<reactive-json:autocomplete-field:input>"
155
+ - param: "limit"
156
+ value: "10"
157
+
158
+ data:
159
+ selectedId: null
160
+ ```
161
+
162
+ ### Multiple selection with a limit
163
+
164
+ Stores up to 3 values as an array. Each selected item is displayed as a removable tag.
165
+
166
+ ```yaml
167
+ renderView:
168
+ - type: AutocompleteField
169
+ dataLocation: ~~.selectedIds
170
+ multiple: true
171
+ maxItems: 3
172
+ placeholder: "Add items (max 3)…"
173
+ src:
174
+ - "/api/items"
175
+ - param: "search"
176
+ value: "<reactive-json:autocomplete-field:input>"
177
+ - param: "limit"
178
+ value: "10"
179
+ - type: p
180
+ content:
181
+ - "Selected IDs: "
182
+ - type: Join
183
+ content: ~~.selectedIds
184
+
185
+ data:
186
+ selectedIds: []
187
+ ```
188
+
189
+ ### Custom templates
190
+
191
+ Use `itemTemplate` and `selectedTemplate` to render richer content. Both templates have access to all fields returned by the backend via `~.`.
192
+
193
+ ```yaml
194
+ - type: AutocompleteField
195
+ dataLocation: ~~.selectedItem
196
+ placeholder: "Search…"
197
+ src:
198
+ - "/api/items"
199
+ - param: "search"
200
+ value: "<reactive-json:autocomplete-field:input>"
201
+ itemTemplate:
202
+ type: div
203
+ content:
204
+ - type: strong
205
+ content: ~.label
206
+ - " (#"
207
+ - ~.value
208
+ - ")"
209
+ selectedTemplate:
210
+ type: span
211
+ content:
212
+ - ~.label
213
+ - " ✓"
214
+ ```
215
+
216
+ ## Limitations
217
+
218
+ - Requires an external API endpoint; no built-in static options support.
219
+ - The dropdown only renders while the user is actively typing (results are not re-fetched on re-open without re-typing).
220
+ - In multiple mode, selected items' display data is kept in local React state and may be lost on page reload unless persisted separately.
221
+ - Styling must be provided via external CSS targeting the `.rj-autocomplete*` classes, or via `attributes.style`.
222
+ - No built-in keyboard navigation for the dropdown.
223
+
224
+ templates: {}
225
+ data: {}
@@ -0,0 +1,108 @@
1
+ # Join
2
+
3
+ The `Join` component concatenates an array of values into a single string, with a configurable separator. It is useful for displaying lists of scalar values (IDs, labels, tags, etc.) inline.
4
+
5
+ ## Basic Syntax
6
+
7
+ ```yaml
8
+ - type: Join
9
+ content: ~~.myArray
10
+ separator: ", "
11
+ ```
12
+
13
+ ## Properties
14
+
15
+ - `content` (array, required): The array to join. Supports template references such as `~~.myArray` or `~.items`. Non-array values are coerced to string and displayed as-is.
16
+ - `separator` (string, optional): The string used between each element. Defaults to `", "`.
17
+ - `attributes` (object, optional): Additional attributes for the root element.
18
+ - `actions` (array, optional): Actions to execute based on component state.
19
+
20
+ ## Examples
21
+
22
+ ### Basic join with default separator
23
+
24
+ ```yaml
25
+ renderView:
26
+ - type: Join
27
+ content: ~~.tags
28
+
29
+ data:
30
+ tags:
31
+ - "react"
32
+ - "yaml"
33
+ - "json"
34
+ ```
35
+
36
+ Renders: `react, yaml, json`
37
+
38
+ ### Custom separator
39
+
40
+ ```yaml
41
+ renderView:
42
+ - type: Join
43
+ content: ~~.ids
44
+ separator: " | "
45
+
46
+ data:
47
+ ids:
48
+ - 1
49
+ - 2
50
+ - 3
51
+ ```
52
+
53
+ Renders: `1 | 2 | 3`
54
+
55
+ ### Used inside a sentence
56
+
57
+ ```yaml
58
+ renderView:
59
+ - type: p
60
+ content:
61
+ - "Selected items: "
62
+ - type: Join
63
+ content: ~~.selectedIds
64
+ separator: ", "
65
+
66
+ data:
67
+ selectedIds:
68
+ - 42
69
+ - 7
70
+ - 15
71
+ ```
72
+
73
+ ### With template-scoped data
74
+
75
+ ```yaml
76
+ renderView:
77
+ - type: Switch
78
+ content: ~~.users
79
+ singleOption:
80
+ load: userRow
81
+
82
+ templates:
83
+ userRow:
84
+ type: div
85
+ content:
86
+ - "Roles: "
87
+ - type: Join
88
+ content: ~.roles
89
+ separator: " / "
90
+
91
+ data:
92
+ users:
93
+ - name: "Alice"
94
+ roles: ["admin", "editor"]
95
+ - name: "Bob"
96
+ roles: ["viewer"]
97
+ ```
98
+
99
+ ## Notes
100
+
101
+ - If `content` evaluates to a non-array value, it is rendered as a plain string (no separator applied).
102
+ - Null or undefined `content` renders nothing.
103
+ - Array elements are joined using JavaScript's native `.join()`, so objects will render as `[object Object]`. Use this component with arrays of primitives (strings, numbers).
104
+
105
+ ## Limitations
106
+
107
+ - No support for rendering rich content (HTML, components) between items — use `Switch` with a template for that.
108
+ - No per-item formatting; all elements are joined as plain strings.
@@ -0,0 +1,113 @@
1
+ renderView:
2
+ - type: Markdown
3
+ content: |
4
+ # Join
5
+
6
+ The `Join` component concatenates an array of values into a single string, with a configurable separator. It is useful for displaying lists of scalar values (IDs, labels, tags, etc.) inline.
7
+
8
+ - type: Markdown
9
+ content: |
10
+ ## Basic Syntax
11
+
12
+ ```yaml
13
+ - type: Join
14
+ content: ~~.myArray
15
+ separator: ", "
16
+ ```
17
+
18
+ ## Properties
19
+
20
+ - type: DefinitionList
21
+ content:
22
+ - term:
23
+ code: content
24
+ after: "(array, required)"
25
+ details: "The array to join. Supports template references such as ~~.myArray or ~.items. Non-array values are coerced to string and displayed as-is."
26
+ - term:
27
+ code: separator
28
+ after: '(string, optional, default: ", ")'
29
+ details: "The string used between each element."
30
+ - term:
31
+ code: attributes
32
+ after: "(object, optional)"
33
+ details: "Additional attributes for the root element."
34
+ - term:
35
+ code: actions
36
+ after: "(array, optional)"
37
+ details: "Actions to execute based on component state."
38
+
39
+ - type: RjBuildDescriber
40
+ title: "Basic join with default separator"
41
+ description: "Join an array of strings with the default comma-space separator."
42
+ toDescribe:
43
+ renderView:
44
+ - type: p
45
+ content:
46
+ - "Tags: "
47
+ - type: Join
48
+ content: ~~.tags
49
+ data:
50
+ tags:
51
+ - "react"
52
+ - "yaml"
53
+ - "json"
54
+
55
+ - type: RjBuildDescriber
56
+ title: "Custom separator"
57
+ description: "Use a pipe separator to display a list of IDs."
58
+ toDescribe:
59
+ renderView:
60
+ - type: p
61
+ content:
62
+ - "IDs: "
63
+ - type: Join
64
+ content: ~~.ids
65
+ separator: " | "
66
+ - type: div
67
+ attributes:
68
+ class: "mt-5 p-2.5 rounded border border-gray-300 dark:border-gray-600"
69
+ content:
70
+ - type: strong
71
+ content: "Raw array: "
72
+ - type: Code
73
+ content: ~~.ids
74
+ data:
75
+ ids:
76
+ - 42
77
+ - 7
78
+ - 15
79
+
80
+ - type: RjBuildDescriber
81
+ title: "Inside a sentence"
82
+ description: "Embed a Join inside a paragraph to display selected values inline."
83
+ toDescribe:
84
+ renderView:
85
+ - type: p
86
+ content:
87
+ - "Selected items: "
88
+ - type: strong
89
+ content:
90
+ type: Join
91
+ content: ~~.selectedIds
92
+ separator: ", "
93
+ data:
94
+ selectedIds:
95
+ - 42
96
+ - 7
97
+ - 15
98
+
99
+ - type: Markdown
100
+ content: |
101
+ ## Notes
102
+
103
+ - If `content` evaluates to a non-array value, it is rendered as a plain string (no separator applied).
104
+ - Null or undefined `content` renders nothing.
105
+ - Array elements are joined using JavaScript's native `.join()`, so objects will render as `[object Object]`. Use this component with arrays of primitives (strings, numbers).
106
+
107
+ ## Limitations
108
+
109
+ - No support for rendering rich content (HTML, components) between items — use `Switch` with a template for that.
110
+ - No per-item formatting; all elements are joined as plain strings.
111
+
112
+ templates: {}
113
+ data: {}
@@ -266,15 +266,112 @@ additionalDataSource:
266
266
  ```
267
267
 
268
268
  ### Properties
269
- - **`src`** (required): URL of the data source. Can be a **string** (used as-is) or an **array of segments** that are resolved and concatenated (see [Dynamic URLs](#dynamic-urls-with-src-as-array) below)
270
- - **`path`** (optional): Path where to place the data (template syntax)
271
- - **`method`** (optional): HTTP method (GET, POST, etc.)
272
- - **`dataMapping`** (optional): Configure selective data dispatch using mapping processors
273
- - **`blocking`** (optional): If `true`, waits for loading before displaying
269
+ - **`src`** (required): URL of the data source. Can be a **string** (used as-is) or an **array of segments** see [Dynamic URLs](#dynamic-urls-with-src-as-array) below.
270
+ - **`path`** (optional): Path where to place the data (template syntax).
271
+ - **`method`** (optional): HTTP method (GET, POST, etc.).
272
+ - **`dataMapping`** (optional): Configure selective data dispatch using mapping processors.
273
+ - **`blocking`** (optional): If `true`, waits for loading before displaying.
274
+ - **`fallbackDataSource`** (optional): An alternate source tried when the primary fails — see [Fallback Sources](#fallback-sources) below.
274
275
 
275
276
  ### Dynamic URLs with `src` as Array
276
277
 
277
- When `src` is an array, each segment is resolved individually and then concatenated into the final URL. Segments starting with `~~.` are treated as references to the store data and are replaced with their resolved values.
278
+ When `src` is an array, each element is processed individually and the results are assembled into the final URL. The array can mix three kinds of elements:
279
+
280
+ #### 1. Plain strings and store references
281
+
282
+ A plain string is used as a literal. A string starting with `~~.` or `~.` is resolved from the root store data (both notations are equivalent in this context).
283
+
284
+ ```yaml
285
+ additionalDataSource:
286
+ - src:
287
+ - "/api/items/"
288
+ - ~~.itemId # resolved from root data
289
+ - "/details"
290
+ path: ~~.itemDetails
291
+ blocking: true
292
+ ```
293
+
294
+ #### 2. Segment objects — `{ segment, required? }`
295
+
296
+ A segment object resolves a dynamic value and inserts it as a path part.
297
+
298
+ ```yaml
299
+ additionalDataSource:
300
+ - src:
301
+ - "/api/"
302
+ - segment: ~~.category # resolved as a path segment
303
+ - "/items"
304
+ path: ~~.items
305
+ blocking: true
306
+ ```
307
+
308
+ When `required: true` is set and the segment resolves to `null` or empty, the entire URL is aborted (returns `null`) instead of producing a broken URL. This triggers the `fallbackDataSource` if one is defined, otherwise the source is skipped with a warning.
309
+
310
+ ```yaml
311
+ additionalDataSource:
312
+ - src:
313
+ - "/api/items/"
314
+ - segment: ~~.requiredId
315
+ required: true # abort URL if null
316
+ fallbackDataSource:
317
+ src: "/api/items/default"
318
+ path: ~~.item
319
+ path: ~~.item
320
+ blocking: true
321
+ ```
322
+
323
+ #### 3. Query param objects — `{ param, value, required? }`
324
+
325
+ A param object adds a key-value pair to the URL query string. Both the key and the value accept store references.
326
+
327
+ ```yaml
328
+ additionalDataSource:
329
+ - src:
330
+ - "/api/items"
331
+ - param: id
332
+ value: ~~.itemId # ?id=<itemId>
333
+ - param: ~~.filterParamName
334
+ value: ~~.filterValue # dynamic key and value
335
+ path: ~~.items
336
+ blocking: true
337
+ ```
338
+
339
+ **Null handling for params:**
340
+ - If either the key or the value resolves to `null`/empty and `required` is absent or `false`, the param is **silently omitted** from the URL.
341
+ - If either resolves to `null`/empty and `required: true` is set, the entire URL is **aborted**, triggering `fallbackDataSource` if defined.
342
+
343
+ ```yaml
344
+ additionalDataSource:
345
+ - src:
346
+ - "/api/search"
347
+ - param: q
348
+ value: ~~.searchQuery # omitted if null
349
+ - param: type
350
+ value: ~~.filterType
351
+ required: true # abort if null
352
+ path: ~~.results
353
+ blocking: true
354
+ ```
355
+
356
+ #### Mixing all three types
357
+
358
+ Path parts (plain strings, `~~.`/`~.` strings, and `segment` objects) are concatenated in order. All `param` objects are collected and appended as a query string after the path.
359
+
360
+ ```yaml
361
+ additionalDataSource:
362
+ - src:
363
+ - "/api/"
364
+ - segment: ~~.category # path: /api/electronics
365
+ required: true # abort URL if category is null
366
+ - "/items" # path: /api/electronics/items
367
+ - param: id
368
+ value: ~~.itemId # ?id=42
369
+ - param: ~~.extraKey
370
+ value: ~~.extraValue # &q=hello
371
+ path: ~~.result
372
+ blocking: true
373
+ # Resolved URL: /api/electronics/items?id=42&q=hello
374
+ ```
278
375
 
279
376
  This is particularly useful when an RjBuild is loaded inside a `ReactiveJsonSubroot` with `dataOverride`, where dynamic values (like entity IDs) are injected by the parent.
280
377
 
@@ -288,25 +385,54 @@ This is particularly useful when an RjBuild is loaded inside a `ReactiveJsonSubr
288
385
  ```
289
386
 
290
387
  ```yaml
291
- # TimeLogManager.yaml — uses taskId in additionalDataSource
388
+ # TimeLogManager.yaml — uses taskId as a query param
292
389
  additionalDataSource:
293
390
  - src:
294
- - "/api/time-logs?filter[task]="
295
- - ~~.taskId
391
+ - "/api/time-logs"
392
+ - param: "filter[task]"
393
+ value: ~~.taskId
394
+ required: true
296
395
  path: ~~.timeLogs
297
396
  blocking: true
298
397
 
299
398
  data:
300
- taskId: "" # Will be overridden by dataOverride
399
+ taskId: "" # Will be overridden by dataOverride
301
400
  timeLogs: []
302
401
  ```
303
402
 
304
- In this example, if `taskId` is `"42"`, the resolved URL will be `/api/time-logs?filter[task]=42`.
403
+ ### Fallback Sources
404
+
405
+ The `fallbackDataSource` property defines an alternate source that is tried automatically when the primary source cannot be used. It accepts the same structure as a regular `additionalDataSource` item, including its own `fallbackDataSource` for chaining.
406
+
407
+ A fallback is triggered in two situations:
408
+
409
+ 1. **The URL cannot be resolved** — a segment or param marked `required: true` resolved to `null` or empty.
410
+ 2. **The HTTP request fails** — the server returns an error (4xx, 5xx, network failure, etc.).
305
411
 
306
- **Rules:**
307
- - Only `~~.` (global/root data) references are supported in `src` segments — `~.` (local template context) is not available during initialization
308
- - If a `~~.` reference resolves to `null` or `undefined`, it is replaced with an empty string and a warning is logged
309
- - When `src` is a plain string, it behaves exactly as before (full backward compatibility)
412
+ ```yaml
413
+ additionalDataSource:
414
+ # Fallback on missing required param
415
+ - src:
416
+ - "/api/items"
417
+ - param: id
418
+ value: ~~.selectedId
419
+ required: true
420
+ path: ~~.item
421
+ fallbackDataSource:
422
+ src: "/api/items/default"
423
+ path: ~~.item
424
+ blocking: true
425
+
426
+ # Fallback on HTTP error
427
+ - src: "/api/live-config"
428
+ path: ~~.config
429
+ fallbackDataSource:
430
+ src: "/api/config-cache"
431
+ path: ~~.config
432
+ blocking: true
433
+ ```
434
+
435
+ When a fallback is triggered, a warning is logged in the console explaining the reason. If no fallback is defined and the primary fails, the source is skipped with a warning.
310
436
 
311
437
  ### Loading Modes
312
438
 
@@ -368,30 +494,47 @@ additionalDataSource:
368
494
  ### Complete Example
369
495
 
370
496
  ```yaml
371
- renderView:
372
- - type: div
373
- content:
374
- - type: h1
375
- content: ["Hello ", ~~.currentUser.name]
376
- - type: p
377
- content: ["Version: ", ~~.systemConfig.version]
378
-
379
497
  data:
380
- currentUser:
381
- name: "Loading..." # Temporary value
382
- systemConfig:
383
- version: "Loading..."
498
+ userId: "42"
499
+ section: "reports"
500
+ formatParam: "json"
501
+ optionalFilter: null # null → param silently omitted
502
+ fallbackSection: "home"
384
503
 
385
504
  additionalDataSource:
386
- # Critical user data (blocking)
505
+ # Static URL simple string form
387
506
  - src: "/api/user-profile.json"
388
507
  path: ~~.currentUser
389
508
  blocking: true
390
-
391
- # System configuration (non-blocking)
392
- - src: "/api/system-config.json"
509
+
510
+ # Dynamic path segment + query params
511
+ - src:
512
+ - "/api/"
513
+ - segment: ~~.section # e.g. /api/reports
514
+ - param: userId
515
+ value: ~~.userId # ?userId=42
516
+ - param: format
517
+ value: ~~.formatParam # &format=json
518
+ - param: filter
519
+ value: ~~.optionalFilter # null → omitted
520
+ path: ~~.sectionData
521
+ blocking: true
522
+
523
+ # Required param with fallback on failure or HTTP error
524
+ - src: "/api/system-config"
393
525
  path: ~~.systemConfig
526
+ fallbackDataSource:
527
+ src: "/api/system-config-cache"
528
+ path: ~~.systemConfig
394
529
  blocking: false
530
+
531
+ renderView:
532
+ - type: div
533
+ content:
534
+ - type: h1
535
+ content: ["Hello ", ~~.currentUser.name]
536
+ - type: p
537
+ content: ["Version: ", ~~.systemConfig.version]
395
538
  ```
396
539
 
397
540
  ## Best Practices
@@ -305,15 +305,100 @@ renderView:
305
305
  content: |
306
306
 
307
307
  ### Properties
308
- - **`src`** (required): URL of the data source. Can be a **string** (used as-is) or an **array of segments** that are resolved and concatenated (see [Dynamic URLs](#dynamic-urls-with-src-as-array) below)
309
- - **`path`** (optional): Path where to place the data (template syntax)
310
- - **`method`** (optional): HTTP method (GET, POST, etc.)
311
- - **`dataMapping`** (optional): Configure selective data dispatch using mapping processors
312
- - **`blocking`** (optional): If `true`, waits for loading before displaying
308
+ - **`src`** (required): URL of the data source. Can be a **string** (used as-is) or an **array of segments** see [Dynamic URLs](#dynamic-urls-with-src-as-array) below.
309
+ - **`path`** (optional): Path where to place the data (template syntax).
310
+ - **`method`** (optional): HTTP method (GET, POST, etc.).
311
+ - **`dataMapping`** (optional): Configure selective data dispatch using mapping processors.
312
+ - **`blocking`** (optional): If `true`, waits for loading before displaying.
313
+ - **`fallbackDataSource`** (optional): An alternate source tried when the primary fails — see [Fallback Sources](#fallback-sources) below.
313
314
 
314
315
  ### Dynamic URLs with `src` as Array
315
316
 
316
- When `src` is an array, each segment is resolved individually and then concatenated into the final URL. Segments starting with `~~.` are treated as references to the store data and are replaced with their resolved values.
317
+ When `src` is an array, each element is processed individually and the results are assembled into the final URL. The array can mix three kinds of elements:
318
+
319
+ #### 1. Plain strings and store references
320
+
321
+ A plain string is used as a literal. A string starting with `~~.` or `~.` is resolved from the root store data (both notations are equivalent in this context).
322
+
323
+ - type: TabbedSerializer
324
+ yamlSerializedContent: |
325
+ additionalDataSource:
326
+ - src:
327
+ - "/api/items/"
328
+ - ~~.itemId # resolved from root data
329
+ - "/details"
330
+ path: ~~.itemDetails
331
+ blocking: true
332
+
333
+ - type: Markdown
334
+ content: |
335
+
336
+ #### 2. Segment objects — `{ segment, required? }`
337
+
338
+ A segment object resolves a dynamic value and inserts it as a path part. When `required: true` is set and the segment resolves to `null` or empty, the entire URL is aborted instead of producing a broken URL. This triggers `fallbackDataSource` if one is defined.
339
+
340
+ - type: TabbedSerializer
341
+ yamlSerializedContent: |
342
+ additionalDataSource:
343
+ - src:
344
+ - "/api/"
345
+ - segment: ~~.category # resolved as a path segment
346
+ required: true # abort URL if null
347
+ - "/items"
348
+ path: ~~.items
349
+ blocking: true
350
+
351
+ - type: Markdown
352
+ content: |
353
+
354
+ #### 3. Query param objects — `{ param, value, required? }`
355
+
356
+ A param object adds a key-value pair to the URL query string. Both the key and the value accept store references.
357
+
358
+ **Null handling:**
359
+ - If either the key or the value resolves to `null`/empty and `required` is absent or `false`, the param is **silently omitted** from the URL.
360
+ - If either resolves to `null`/empty and `required: true` is set, the entire URL is **aborted**, triggering `fallbackDataSource` if defined.
361
+
362
+ - type: TabbedSerializer
363
+ yamlSerializedContent: |
364
+ additionalDataSource:
365
+ - src:
366
+ - "/api/search"
367
+ - param: q
368
+ value: ~~.searchQuery # omitted if null
369
+ - param: ~~.filterParamName # dynamic key
370
+ value: ~~.filterValue # dynamic value
371
+ - param: type
372
+ value: ~~.filterType
373
+ required: true # abort if null
374
+ path: ~~.results
375
+ blocking: true
376
+
377
+ - type: Markdown
378
+ content: |
379
+
380
+ #### Mixing all three types
381
+
382
+ Path parts (plain strings, `~~.`/`~.` strings, and `segment` objects) are concatenated in order. All `param` objects are collected and appended as a query string after the path.
383
+
384
+ - type: TabbedSerializer
385
+ yamlSerializedContent: |
386
+ additionalDataSource:
387
+ - src:
388
+ - "/api/"
389
+ - segment: ~~.category # path: /api/electronics
390
+ required: true # abort URL if category is null
391
+ - "/items" # path: /api/electronics/items
392
+ - param: id
393
+ value: ~~.itemId # ?id=42
394
+ - param: ~~.extraKey
395
+ value: ~~.extraValue # &q=hello
396
+ path: ~~.result
397
+ blocking: true
398
+ # Resolved URL: /api/electronics/items?id=42&q=hello
399
+
400
+ - type: Markdown
401
+ content: |
317
402
 
318
403
  This is particularly useful when an RjBuild is loaded inside a `ReactiveJsonSubroot` with `dataOverride`, where dynamic values (like entity IDs) are injected by the parent.
319
404
 
@@ -327,32 +412,58 @@ renderView:
327
412
  dataOverride:
328
413
  taskId: ~.task.id
329
414
 
330
- - type: Markdown
331
- content: |
332
-
333
415
  - type: TabbedSerializer
334
416
  yamlSerializedContent: |
335
- # TimeLogManager.yaml — uses taskId in additionalDataSource
417
+ # TimeLogManager.yaml — uses taskId as a query param
336
418
  additionalDataSource:
337
419
  - src:
338
- - "/api/time-logs?filter[task]="
339
- - ~~.taskId
420
+ - "/api/time-logs"
421
+ - param: "filter[task]"
422
+ value: ~~.taskId
423
+ required: true
340
424
  path: ~~.timeLogs
341
425
  blocking: true
342
426
 
343
427
  data:
344
- taskId: "" # Will be overridden by dataOverride
428
+ taskId: "" # Will be overridden by dataOverride
345
429
  timeLogs: []
346
430
 
347
431
  - type: Markdown
348
432
  content: |
349
433
 
350
- In this example, if `taskId` is `"42"`, the resolved URL will be `/api/time-logs?filter[task]=42`.
434
+ ### Fallback Sources
435
+
436
+ The `fallbackDataSource` property defines an alternate source that is tried automatically when the primary source cannot be used. It accepts the same structure as a regular `additionalDataSource` item, including its own `fallbackDataSource` for chaining.
437
+
438
+ A fallback is triggered in two situations:
351
439
 
352
- **Rules:**
353
- - Only `~~.` (global/root data) references are supported in `src` segments `~.` (local template context) is not available during initialization
354
- - If a `~~.` reference resolves to `null` or `undefined`, it is replaced with an empty string and a warning is logged
355
- - When `src` is a plain string, it behaves exactly as before (full backward compatibility)
440
+ 1. **The URL cannot be resolved** — a segment or param marked `required: true` resolved to `null` or empty.
441
+ 2. **The HTTP request fails** the server returns an error (4xx, 5xx, network failure, etc.).
442
+
443
+ When a fallback is triggered, a warning is logged in the console explaining the reason.
444
+
445
+ - type: TabbedSerializer
446
+ yamlSerializedContent: |
447
+ additionalDataSource:
448
+ # Fallback on missing required param
449
+ - src:
450
+ - "/api/items"
451
+ - param: id
452
+ value: ~~.selectedId
453
+ required: true
454
+ path: ~~.item
455
+ fallbackDataSource:
456
+ src: "/api/items/default"
457
+ path: ~~.item
458
+ blocking: true
459
+
460
+ # Fallback on HTTP error
461
+ - src: "/api/live-config"
462
+ path: ~~.config
463
+ fallbackDataSource:
464
+ src: "/api/config-cache"
465
+ path: ~~.config
466
+ blocking: true
356
467
 
357
468
  ### Loading Modes
358
469
 
@@ -434,31 +545,48 @@ renderView:
434
545
 
435
546
  - type: TabbedSerializer
436
547
  yamlSerializedContent: |
437
- renderView:
438
- - type: div
439
- content:
440
- - type: h1
441
- content: ["Hello ", ~~.currentUser.name]
442
- - type: p
443
- content: ["Version: ", ~~.systemConfig.version]
444
-
445
548
  data:
446
- currentUser:
447
- name: "Loading..." # Temporary value
448
- systemConfig:
449
- version: "Loading..."
549
+ userId: "42"
550
+ section: "reports"
551
+ formatParam: "json"
552
+ optionalFilter: null # null → param silently omitted
450
553
 
451
554
  additionalDataSource:
452
- # Critical user data (blocking)
555
+ # Static URL simple string form
453
556
  - src: "/api/user-profile.json"
454
557
  path: ~~.currentUser
455
558
  blocking: true
456
-
457
- # System configuration (non-blocking)
458
- - src: "/api/system-config.json"
559
+
560
+ # Dynamic path segment + query params
561
+ - src:
562
+ - "/api/"
563
+ - segment: ~~.section # e.g. /api/reports
564
+ required: true
565
+ - param: userId
566
+ value: ~~.userId # ?userId=42
567
+ - param: format
568
+ value: ~~.formatParam # &format=json
569
+ - param: filter
570
+ value: ~~.optionalFilter # null → omitted
571
+ path: ~~.sectionData
572
+ blocking: true
573
+
574
+ # Fallback on HTTP error or unavailable source
575
+ - src: "/api/system-config"
459
576
  path: ~~.systemConfig
577
+ fallbackDataSource:
578
+ src: "/api/system-config-cache"
579
+ path: ~~.systemConfig
460
580
  blocking: false
461
581
 
582
+ renderView:
583
+ - type: div
584
+ content:
585
+ - type: h1
586
+ content: ["Hello ", ~~.currentUser.name]
587
+ - type: p
588
+ content: ["Version: ", ~~.systemConfig.version]
589
+
462
590
  - type: Markdown
463
591
  content: |
464
592