@ea-lab/reactive-json-docs 1.2.0 → 1.3.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.
@@ -0,0 +1,384 @@
1
+ # SelectField
2
+
3
+ The `SelectField` component provides a native HTML select dropdown with automatic data synchronization, intelligent value type handling, and support for dynamic options. It combines the simplicity of native HTML with the convenience of automatic data binding.
4
+
5
+ ## Basic Syntax
6
+
7
+ ```yaml
8
+ - type: SelectField
9
+ dataLocation: ~.category
10
+ label: "Select category:"
11
+ options:
12
+ - label: "Choose category..."
13
+ value: ""
14
+ - label: "Technology"
15
+ value: "tech"
16
+ - label: "Sports"
17
+ value: "sports"
18
+ ```
19
+
20
+ ## Properties
21
+
22
+ - `dataLocation` (string, optional): Path to bind the field value in the data context.
23
+ - `defaultFieldValue` (any, optional): Default value when no data is present.
24
+ - `label` (string or View props, optional): Field label text (supports template evaluation and View component rendering).
25
+ - `options` (array, optional): Static array of option objects with `label` and `value` properties.
26
+ - `dynamicOptions` (string, optional): Template path to dynamic options array (e.g., `~.availableCategories`). Takes precedence over `options` if both are provided.
27
+ - `allowEmptyStringAsValue` (boolean, optional): Preserve empty strings as `""` instead of converting to `undefined` (default: `false`).
28
+ - `attributes` (object, optional): Attributes applied to the container div (or merged with inputAttributes if no wrapper).
29
+ - `inputAttributes` (object, optional): Attributes applied directly to the select element.
30
+ - `labelAttributes` (object, optional): Attributes applied to the label (htmlFor is automatically managed).
31
+ - `forceWrapper` (boolean, optional): Forces the presence (true) or absence (false) of the wrapper div. If omitted, wrapper is automatic only if label is present.
32
+ - `actions` (array, optional): Actions to execute based on field state.
33
+
34
+ ## Data Management
35
+
36
+ The component automatically synchronizes its value with the global data context. It handles different value types intelligently:
37
+
38
+ ### Value Type Conversion
39
+
40
+ - **Empty strings**: Become `undefined` by default, or preserved as `""` if `allowEmptyStringAsValue: true`
41
+ - **Boolean strings**: `"true"` becomes boolean `true`, `"false"` becomes boolean `false`
42
+ - **Null string**: `"null"` becomes `null`
43
+ - **Other values**: Stored as strings and matched by string comparison
44
+
45
+ ### Empty String Handling
46
+
47
+ SelectField makes an important distinction between "no selection made" and "explicit selection of empty value":
48
+
49
+ - **Default behavior**: `value: ""` → stored as `undefined`
50
+ - Useful for validation and conditional logic
51
+ - Indicates "no selection made"
52
+ - **With `allowEmptyStringAsValue: true`**: `value: ""` → stored as `""`
53
+ - Semantic meaning: "User explicitly selected the empty option"
54
+ - Useful when empty string is a legitimate business value
55
+
56
+ This distinction is crucial for validation logic and conditional actions in reactive-json.
57
+
58
+ ## Wrapper Control
59
+
60
+ The component uses a flexible wrapper system similar to `Input`, adapting based on the presence of a label and the `forceWrapper` property.
61
+
62
+ ### Default Behavior
63
+
64
+ When no `forceWrapper` is specified, the component automatically determines whether to use a wrapper div. If a label is present, the component wraps both the label and select in a div container. If no label is present, the select is rendered directly without a wrapper.
65
+
66
+ ### Explicit Control with `forceWrapper`
67
+
68
+ You can override the default behavior using the `forceWrapper` property. Setting `forceWrapper: true` will always create a wrapper div, even without a label. Setting `forceWrapper: false` will never create a wrapper, even when a label is present.
69
+
70
+ ### HTML Output Examples
71
+
72
+ **With label (automatic wrapper):**
73
+ ```html
74
+ <div>
75
+ <label htmlFor="select-abc123">Select category:</label>
76
+ <select id="select-abc123">
77
+ <option value="">Choose category...</option>
78
+ <option value="tech">Technology</option>
79
+ </select>
80
+ </div>
81
+ ```
82
+
83
+ **Without label (no wrapper):**
84
+ ```html
85
+ <select id="select-xyz789">
86
+ <option value="">Choose category...</option>
87
+ <option value="tech">Technology</option>
88
+ </select>
89
+ ```
90
+
91
+ ### Attribute Merging
92
+
93
+ When a wrapper is present, the `attributes` are applied to the div container and `inputAttributes` are applied to the select element. When no wrapper is present, both `attributes` and `inputAttributes` are merged and applied to the select element.
94
+
95
+ ## Label Support
96
+
97
+ The `label` property supports both simple strings and View component rendering, allowing for dynamic and complex label content:
98
+
99
+ ```yaml
100
+ - type: SelectField
101
+ dataLocation: ~.category
102
+ label:
103
+ type: div
104
+ content:
105
+ - "Select category ("
106
+ - type: strong
107
+ content: ~.requiredText
108
+ - "):"
109
+ dynamicOptions: ~.categories
110
+ ```
111
+
112
+ ## Option Labels
113
+
114
+ Option labels support template evaluation, allowing dynamic content:
115
+
116
+ ```yaml
117
+ - type: SelectField
118
+ dataLocation: ~.item
119
+ options:
120
+ - label: "Item: ~.itemName"
121
+ value: "item1"
122
+ - label: ["Count: ", ~.count]
123
+ value: "item2"
124
+ ```
125
+
126
+ ## Empty Options Handling
127
+
128
+ If `options` is empty or not an array, the component displays a single option: "No options available". This is useful for conditional rendering scenarios where options may be loaded dynamically.
129
+
130
+ ## Examples
131
+
132
+ ### Basic SelectField
133
+
134
+ ```yaml
135
+ renderView:
136
+ - type: SelectField
137
+ dataLocation: ~.priority
138
+ label: "Priority:"
139
+ options:
140
+ - label: "Select priority"
141
+ value: ""
142
+ - label: "Low"
143
+ value: "low"
144
+ - label: "Medium"
145
+ value: "medium"
146
+ - label: "High"
147
+ value: "high"
148
+
149
+ data:
150
+ priority: ""
151
+ ```
152
+
153
+ ### Boolean and Special Values
154
+
155
+ ```yaml
156
+ renderView:
157
+ - type: SelectField
158
+ dataLocation: ~.isActive
159
+ label: "Status:"
160
+ options:
161
+ - label: "Select status"
162
+ value: ""
163
+ - label: "Active"
164
+ value: "true"
165
+ - label: "Inactive"
166
+ value: "false"
167
+ - label: "Not set"
168
+ value: "null"
169
+
170
+ data:
171
+ isActive: ""
172
+ ```
173
+
174
+ ### Empty String as Value
175
+
176
+ ```yaml
177
+ renderView:
178
+ - type: SelectField
179
+ dataLocation: ~.description
180
+ label: "Description:"
181
+ allowEmptyStringAsValue: true
182
+ options:
183
+ - label: "No description"
184
+ value: ""
185
+ - label: "Brief description"
186
+ value: "brief"
187
+ - label: "Detailed description"
188
+ value: "detailed"
189
+
190
+ data:
191
+ description: ""
192
+ ```
193
+
194
+ ### Dynamic Options
195
+
196
+ ```yaml
197
+ renderView:
198
+ - type: SelectField
199
+ dataLocation: ~.selectedCategory
200
+ label: "Category:"
201
+ dynamicOptions: ~.availableCategories
202
+
203
+ data:
204
+ availableCategories:
205
+ - label: "Technology"
206
+ value: "tech"
207
+ - label: "Sports"
208
+ value: "sports"
209
+ - label: "Music"
210
+ value: "music"
211
+ selectedCategory: ""
212
+ ```
213
+
214
+ ### Custom Attributes
215
+
216
+ ```yaml
217
+ renderView:
218
+ - type: SelectField
219
+ dataLocation: ~.country
220
+ label: "Country:"
221
+ inputAttributes:
222
+ required: true
223
+ style:
224
+ width: "100%"
225
+ padding: "8px"
226
+ attributes:
227
+ style:
228
+ marginBottom: "10px"
229
+ options:
230
+ - label: "Select country"
231
+ value: ""
232
+ - label: "United States"
233
+ value: "us"
234
+ - label: "Canada"
235
+ value: "ca"
236
+
237
+ data:
238
+ country: ""
239
+ ```
240
+
241
+ ### Wrapper Control
242
+
243
+ ```yaml
244
+ renderView:
245
+ # No label → no wrapper automatically
246
+ - type: SelectField
247
+ dataLocation: ~.noWrapper
248
+ options:
249
+ - label: "Option 1"
250
+ value: "opt1"
251
+
252
+ # With label → automatic wrapper
253
+ - type: SelectField
254
+ dataLocation: ~.autoWrapper
255
+ label: "With automatic wrapper:"
256
+ options:
257
+ - label: "Option 1"
258
+ value: "opt1"
259
+
260
+ # Force wrapper even without label
261
+ - type: SelectField
262
+ dataLocation: ~.forceWrapper
263
+ options:
264
+ - label: "Option 1"
265
+ value: "opt1"
266
+ forceWrapper: true
267
+ attributes:
268
+ style:
269
+ border: "2px solid blue"
270
+ padding: "10px"
271
+
272
+ # No wrapper even with label
273
+ - type: SelectField
274
+ dataLocation: ~.noWrapperForced
275
+ label: "Label without wrapper:"
276
+ options:
277
+ - label: "Option 1"
278
+ value: "opt1"
279
+ forceWrapper: false
280
+
281
+ data:
282
+ noWrapper: ""
283
+ autoWrapper: ""
284
+ forceWrapper: ""
285
+ noWrapperForced: ""
286
+ ```
287
+
288
+ ### Custom Label Attributes
289
+
290
+ ```yaml
291
+ renderView:
292
+ - type: SelectField
293
+ dataLocation: ~.customLabel
294
+ label: "Custom label:"
295
+ labelAttributes:
296
+ style:
297
+ color: "blue"
298
+ fontWeight: "bold"
299
+ fontSize: "14px"
300
+ className: "custom-label"
301
+ options:
302
+ - label: "Option 1"
303
+ value: "opt1"
304
+
305
+ data:
306
+ customLabel: ""
307
+ ```
308
+
309
+ ### With Actions
310
+
311
+ ```yaml
312
+ renderView:
313
+ - type: SelectField
314
+ dataLocation: ~.category
315
+ label: "Category:"
316
+ options:
317
+ - label: "Select category"
318
+ value: ""
319
+ - label: "Technology"
320
+ value: "tech"
321
+ - label: "Sports"
322
+ value: "sports"
323
+ actions:
324
+ - what: setData
325
+ when: ~.category
326
+ isEmpty: true
327
+ path: ~.hasCategory
328
+ value: false
329
+ - what: setData
330
+ when: ~.category
331
+ isNot: ""
332
+ path: ~.hasCategory
333
+ value: true
334
+
335
+ data:
336
+ category: ""
337
+ hasCategory: false
338
+ ```
339
+
340
+ ### Multiple Select (using `multiple` attribute)
341
+
342
+ ```yaml
343
+ renderView:
344
+ - type: SelectField
345
+ dataLocation: ~.selectedItems
346
+ label: "Select multiple items:"
347
+ inputAttributes:
348
+ multiple: true
349
+ options:
350
+ - label: "Item 1"
351
+ value: "item1"
352
+ - label: "Item 2"
353
+ value: "item2"
354
+ - label: "Item 3"
355
+ value: "item3"
356
+
357
+ data:
358
+ selectedItems: []
359
+ ```
360
+
361
+ **Note**: For multiple selection, the component stores an array. However, native HTML select multiple is limited. Consider using `CheckBoxField` with `multiple: true` for better UX.
362
+
363
+ ## Advantages
364
+
365
+ - **No external dependencies**: Works without any CSS framework
366
+ - **Full control**: Custom styling and behavior
367
+ - **Performance**: Lighter than component libraries
368
+ - **Accessibility**: Direct control over ARIA attributes, automatic htmlFor
369
+ - **Automatic synchronization**: Unlike raw HTML elements that require manual setData actions
370
+ - **Flexible wrapper**: Avoids unnecessary HTML when not needed
371
+ - **Intelligent value handling**: Automatic conversion of boolean and null strings
372
+ - **Dynamic options**: Options can be provided via template evaluation using `dynamicOptions`
373
+ - **Label flexibility**: Supports both simple strings and View component rendering
374
+ - **Empty state handling**: Gracefully handles empty options
375
+
376
+ ## Limitations
377
+
378
+ - No built-in validation beyond HTML5 select validation
379
+ - No support for option grouping (use multiple SelectField components or custom styling)
380
+ - Styling must be provided via external CSS or style attributes
381
+ - Multiple selection via `multiple` attribute has limited UX (consider CheckBoxField for better multiple selection)
382
+ - Template evaluation for option labels should return strings or arrays of strings
383
+ - Empty string handling requires explicit `allowEmptyStringAsValue` for semantic distinction
384
+
@@ -0,0 +1,252 @@
1
+ renderView:
2
+ - type: Markdown
3
+ content: |
4
+ # SelectField
5
+
6
+ The `SelectField` component provides a native HTML select dropdown with automatic data synchronization, intelligent value type handling, and support for dynamic options. It combines the simplicity of native HTML with the convenience of automatic data binding.
7
+
8
+ - type: Markdown
9
+ content: |
10
+ ## Basic Syntax
11
+
12
+ ```yaml
13
+ - type: SelectField
14
+ dataLocation: ~.category
15
+ label: "Select category:"
16
+ options:
17
+ - label: "Choose category..."
18
+ value: ""
19
+ - label: "Technology"
20
+ value: "tech"
21
+ - label: "Sports"
22
+ value: "sports"
23
+ ```
24
+
25
+ ## Properties
26
+
27
+ - type: DefinitionList
28
+ content:
29
+ - term:
30
+ code: dataLocation
31
+ after: "(string, optional)"
32
+ details: "Path to bind the field value in the data context."
33
+ - term:
34
+ code: defaultFieldValue
35
+ after: "(any, optional)"
36
+ details: "Default value when no data is present."
37
+ - term:
38
+ code: label
39
+ after: "(string or View props, optional)"
40
+ details: "Field label text (supports template evaluation and View component rendering)."
41
+ - term:
42
+ code: options
43
+ after: "(array, optional)"
44
+ details:
45
+ type: Markdown
46
+ content: "Static array of option objects with `label` and `value` properties."
47
+ - term:
48
+ code: dynamicOptions
49
+ after: "(string, optional)"
50
+ details:
51
+ type: Markdown
52
+ content: "Template path to dynamic options array (e.g., `~.availableCategories`). Takes precedence over `options` if both are provided."
53
+ - term:
54
+ code: allowEmptyStringAsValue
55
+ after: "(boolean, optional)"
56
+ details: "Preserve empty strings as `\"\"` instead of converting to `undefined` (default: `false`)."
57
+ - term:
58
+ code: attributes
59
+ after: "(object, optional)"
60
+ details: "Attributes applied to the container div (or merged with inputAttributes if no wrapper)."
61
+ - term:
62
+ code: inputAttributes
63
+ after: "(object, optional)"
64
+ details: "Attributes applied directly to the select element."
65
+ - term:
66
+ code: labelAttributes
67
+ after: "(object, optional)"
68
+ details: "Attributes applied to the label (htmlFor is automatically managed)."
69
+ - term:
70
+ code: forceWrapper
71
+ after: "(boolean, optional)"
72
+ details: "Forces the presence (true) or absence (false) of the wrapper div. If omitted, wrapper is automatic only if label is present."
73
+ - term:
74
+ code: actions
75
+ after: "(array, optional)"
76
+ details: "Actions to execute based on field state."
77
+
78
+ - type: Markdown
79
+ content: |
80
+ ## Data Management
81
+
82
+ The component automatically synchronizes its value with the global data context. It handles different value types intelligently:
83
+
84
+ ### Value Type Conversion
85
+
86
+ - **Empty strings**: Become `undefined` by default, or preserved as `""` if `allowEmptyStringAsValue: true`
87
+ - **Boolean strings**: `"true"` becomes boolean `true`, `"false"` becomes boolean `false`
88
+ - **Null string**: `"null"` becomes `null`
89
+ - **Other values**: Stored as strings and matched by string comparison
90
+
91
+ ### Empty String Handling
92
+
93
+ SelectField makes an important distinction between "no selection made" and "explicit selection of empty value":
94
+
95
+ - **Default behavior**: `value: ""` → stored as `undefined`
96
+ - Useful for validation and conditional logic
97
+ - Indicates "no selection made"
98
+ - **With `allowEmptyStringAsValue: true`**: `value: ""` → stored as `""`
99
+ - Semantic meaning: "User explicitly selected the empty option"
100
+ - Useful when empty string is a legitimate business value
101
+
102
+ This distinction is crucial for validation logic and conditional actions in reactive-json.
103
+
104
+ - type: RjBuildDescriber
105
+ title: "Basic SelectField"
106
+ description: "Simple dropdown selection"
107
+ toDescribe:
108
+ renderView:
109
+ - type: SelectField
110
+ dataLocation: ~.priority
111
+ label: "Priority:"
112
+ options:
113
+ - label: "Select priority"
114
+ value: ""
115
+ - label: "Low"
116
+ value: "low"
117
+ - label: "Medium"
118
+ value: "medium"
119
+ - label: "High"
120
+ value: "high"
121
+ - type: div
122
+ attributes:
123
+ class: "mt-5 p-2.5 rounded border border-gray-300 dark:border-gray-600"
124
+ content:
125
+ - type: strong
126
+ content: "Selected priority: "
127
+ - ~.priority
128
+ data:
129
+ priority: ""
130
+
131
+ - type: RjBuildDescriber
132
+ title: "Boolean and Special Values"
133
+ description: "Handling boolean and null values"
134
+ toDescribe:
135
+ renderView:
136
+ - type: SelectField
137
+ dataLocation: ~.isActive
138
+ label: "Status:"
139
+ options:
140
+ - label: "Select status"
141
+ value: ""
142
+ - label: "Active"
143
+ value: "true"
144
+ - label: "Inactive"
145
+ value: "false"
146
+ - label: "Not set"
147
+ value: "null"
148
+ - type: div
149
+ attributes:
150
+ class: "mt-5 p-2.5 rounded border border-gray-300 dark:border-gray-600"
151
+ content:
152
+ - type: strong
153
+ content: "Status value: "
154
+ - ~.isActive
155
+ - type: div
156
+ attributes:
157
+ class: "mt-1 text-xs text-gray-600 dark:text-gray-400"
158
+ content:
159
+ - "Type: "
160
+ - type: Code
161
+ content: ~.isActive
162
+ data:
163
+ isActive: ""
164
+
165
+ - type: RjBuildDescriber
166
+ title: "Empty String as Value"
167
+ description: "Preserving empty strings as legitimate values"
168
+ toDescribe:
169
+ renderView:
170
+ - type: SelectField
171
+ dataLocation: ~.description
172
+ label: "Description:"
173
+ allowEmptyStringAsValue: true
174
+ options:
175
+ - label: "No description"
176
+ value: ""
177
+ - label: "Brief description"
178
+ value: "brief"
179
+ - label: "Detailed description"
180
+ value: "detailed"
181
+ - type: div
182
+ attributes:
183
+ class: "mt-5 p-2.5 rounded border border-gray-300 dark:border-gray-600"
184
+ content:
185
+ - type: strong
186
+ content: "Selected description: "
187
+ - type: Code
188
+ content: ~.description
189
+ - type: div
190
+ attributes:
191
+ class: "mt-1 text-xs text-gray-600 dark:text-gray-400"
192
+ content:
193
+ - "Note: Empty string is preserved as \"\" (not undefined)"
194
+ data:
195
+ description: ""
196
+
197
+ - type: RjBuildDescriber
198
+ title: "Dynamic Options"
199
+ description: "Options provided via template evaluation using dynamicOptions"
200
+ toDescribe:
201
+ renderView:
202
+ - type: SelectField
203
+ dataLocation: ~.selectedCategory
204
+ label: "Category:"
205
+ dynamicOptions: ~.availableCategories
206
+ - type: div
207
+ attributes:
208
+ class: "mt-5 p-2.5 rounded border border-gray-300 dark:border-gray-600"
209
+ content:
210
+ - type: strong
211
+ content: "Selected category: "
212
+ - ~.selectedCategory
213
+ data:
214
+ availableCategories:
215
+ - label: "Technology"
216
+ value: "tech"
217
+ - label: "Sports"
218
+ value: "sports"
219
+ - label: "Music"
220
+ value: "music"
221
+ - label: "Science"
222
+ value: "science"
223
+ selectedCategory: ""
224
+
225
+
226
+ - type: Markdown
227
+ content: |
228
+ ## Advantages
229
+
230
+ - **No external dependencies**: Works without any CSS framework
231
+ - **Full control**: Custom styling and behavior
232
+ - **Performance**: Lighter than component libraries
233
+ - **Accessibility**: Direct control over ARIA attributes, automatic htmlFor
234
+ - **Automatic synchronization**: Unlike raw HTML elements that require manual setData actions
235
+ - **Flexible wrapper**: Avoids unnecessary HTML when not needed
236
+ - **Intelligent value handling**: Automatic conversion of boolean and null strings
237
+ - **Dynamic options**: Options can be provided via template evaluation using `dynamicOptions`
238
+ - **Label flexibility**: Supports both simple strings and View component rendering
239
+ - **Empty state handling**: Gracefully handles empty options
240
+
241
+ ## Limitations
242
+
243
+ - No built-in validation beyond HTML5 select validation
244
+ - No support for option grouping (use multiple SelectField components or custom styling)
245
+ - Styling must be provided via external CSS or style attributes
246
+ - Multiple selection via `multiple` attribute has limited UX (consider CheckBoxField for better multiple selection)
247
+ - Template evaluation for option labels should return strings or arrays of strings
248
+ - Empty string handling requires explicit `allowEmptyStringAsValue` for semantic distinction
249
+
250
+ templates: {}
251
+ data: {}
252
+