@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.
- package/package.json +2 -2
- package/public/rjbuild/docs/core/element/form/CheckBoxField.md +364 -0
- package/public/rjbuild/docs/core/element/form/CheckBoxField.yaml +222 -0
- package/public/rjbuild/docs/core/element/form/SelectField.md +384 -0
- package/public/rjbuild/docs/core/element/form/SelectField.yaml +252 -0
- package/public/rjbuild/docs/core/element/form/TextAreaField.md +297 -0
- package/public/rjbuild/docs/core/element/form/TextAreaField.yaml +139 -0
- package/public/rjbuild/docs/core/example/bulk-actions.md +405 -0
- package/public/rjbuild/docs/core/example/bulk-actions.yaml +514 -0
- package/public/rjbuild/docs/core/example/editable-modal-in-row.md +281 -0
- package/public/rjbuild/docs/core/example/editable-modal-in-row.yaml +415 -0
- package/public/rjbuild/docs/getting-started/rjbuild-structure.md +24 -0
- package/public/rjbuild/docs/getting-started/rjbuild-structure.yaml +26 -0
- /package/public/rjbuild/docs/{integration/bootstrap → core}/element/form/formElementsCommon.md +0 -0
|
@@ -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
|
+
|