@ea-lab/reactive-json-docs 1.3.1 → 1.4.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ea-lab/reactive-json-docs",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
4
4
  "description": "Complete documentation for Reactive-JSON - Components, examples and LLM-parsable guides",
5
5
  "main": "public/rjbuild/docs/index.yaml",
6
6
  "files": [
@@ -26,7 +26,7 @@
26
26
  "private": false,
27
27
  "devDependencies": {
28
28
  "@craco/craco": "^7.1.0",
29
- "@ea-lab/reactive-json": "^1.2.0",
29
+ "@ea-lab/reactive-json": "^1.3.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,42 +8,73 @@ 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
11
+ # Add CSS class (string mode)
12
12
  - what: setAttributeValue
13
13
  name: "class"
14
14
  value: "active"
15
15
 
16
- # Replace attribute value
16
+ # Replace attribute value (string mode)
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: "var(--bs-secondary-bg-subtle, rgba(0, 0, 0, 0.05))"
21
28
  ```
22
29
 
23
30
  ## Properties
24
31
 
25
32
  - **name** *(string, required)*: The name of the attribute to modify.
26
33
  - **mode** *(string, optional)*: The modification mode. Default: `"append"`.
27
- - `"append"`: Adds the value to the existing attribute value (space-separated).
34
+ - `"append"`: Adds the value to the existing attribute value (space-separated for strings, merges properties for objects).
28
35
  - `"replace"`: Completely replaces the existing attribute value.
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).
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).
32
41
 
33
42
  ## Behavior
34
43
 
44
+ The transformer operates in two distinct modes based on the `value` type:
45
+
46
+ ### String Mode (when `value` is a string)
47
+
35
48
  - **Append mode**: Adds the new value to the existing attribute, separated by the specified separator.
36
49
  - **Replace mode**: Completely overwrites the existing attribute value.
37
50
  - **Duplicate prevention**: In append mode, prevents adding duplicate values when enabled.
38
51
 
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
+
39
68
  ## Common Use Cases
40
69
 
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.
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
45
76
 
46
- ## Example
77
+ ### String Mode Example
47
78
 
48
79
  ```yaml
49
80
  renderView:
@@ -61,6 +92,8 @@ renderView:
61
92
  margin: "10px 0"
62
93
  width: "300px"
63
94
  display: "block"
95
+ backgroundColor: "var(--bs-secondary-bg-subtle, rgba(0, 0, 0, 0.05))"
96
+ color: "#212529"
64
97
  attributeTransforms:
65
98
  - what: setAttributeValue
66
99
  name: "class"
@@ -91,11 +124,81 @@ data:
91
124
  input_data: ""
92
125
  ```
93
126
 
127
+ ### Object Mode Example (Style Merging)
128
+
129
+ ```yaml
130
+ renderView:
131
+ - type: div
132
+ attributes:
133
+ style:
134
+ padding: "20px"
135
+ borderWidth: "2px"
136
+ borderStyle: "solid"
137
+ borderColor: "#007bff #007bff"
138
+ borderRadius: "4px"
139
+ backgroundColor: "var(--bs-secondary-bg-subtle, rgba(0, 0, 0, 0.05))"
140
+ color: "#212529"
141
+ attributeTransforms:
142
+ # Merge additional style properties without losing existing ones
143
+ - what: setAttributeValue
144
+ name: "style"
145
+ value:
146
+ borderColor: "#007bff var(--bs-primary, #3b82f6)"
147
+ when: ~.isHighlighted
148
+ is: true
149
+ # Result when isHighlighted is true:
150
+ # The modification changes the highlight color for vertical borders (left and right)
151
+ # borderColor becomes: "#007bff var(--bs-primary, #3b82f6)"
152
+ # (horizontal borders stay #007bff, vertical borders change to primary color)
153
+
154
+ data:
155
+ isHighlighted: false
156
+ ```
157
+
158
+ ### Object Mode Replace Example
159
+
160
+ ```yaml
161
+ renderView:
162
+ - type: div
163
+ attributes:
164
+ style:
165
+ padding: "10px"
166
+ border: "2px solid #007bff"
167
+ backgroundColor: "var(--bs-secondary-bg-subtle, rgba(0, 0, 0, 0.05))"
168
+ color: "#212529"
169
+ attributeTransforms:
170
+ # Completely replace the style object
171
+ - what: setAttributeValue
172
+ name: "style"
173
+ mode: "replace"
174
+ value:
175
+ backgroundColor: "var(--bs-primary-bg-subtle, #d4f0ec)"
176
+ color: "var(--bs-primary-text-emphasis, #2b6b5a)"
177
+ padding: "15px"
178
+ borderRadius: "8px"
179
+ border: "2px solid var(--bs-primary, #44a08d)"
180
+ # Result:
181
+ # style: {
182
+ # backgroundColor: "var(--bs-primary-bg-subtle, #d4f0ec)",
183
+ # color: "var(--bs-primary-text-emphasis, #2b6b5a)",
184
+ # padding: "15px",
185
+ # borderRadius: "8px",
186
+ # border: "2px solid var(--bs-primary, #44a08d)"
187
+ # }
188
+ # (original styles are completely replaced)
189
+ ```
190
+
94
191
  ## Notes
95
192
 
96
193
  - **Pre-render execution**: This transformer modifies attributes before the component renders, ensuring child components receive the transformed attributes.
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.
194
+ - **Mode detection**: The transformer automatically detects whether to use string mode or object mode based on the `value` type after template evaluation.
195
+ - **Append mode behavior**:
196
+ - **String mode**: Respects existing attribute values, adding new values separated by the specified separator.
197
+ - **Object mode**: Merges properties property by property, applying string append logic where both values are strings, otherwise replacing with the new value.
198
+ - **Replace mode**: Use when you need complete control over the attribute value. In object mode, completely replaces the entire object.
199
+ - **Duplicate prevention**: Only applies to append mode, and works for string values in both string mode and object mode.
200
+ - **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).
201
+ - **Extended properties vs shorthand**: When transformations are required, prefer using extended CSS properties (e.g., `borderWidth`, `borderStyle`, `borderColor`) instead of shorthand properties (e.g., `border`). This ensures the browser handles property modifications correctly. When you modify a single property like `borderColor` on an element that uses the shorthand `border`, the browser may decompose the shorthand into individual properties, which can lead to unexpected behavior. Using extended properties from the start avoids this issue.
100
202
  - **Template evaluation**: The value property supports full template evaluation including `~.localData`, `~~.globalData`, `~>nearestKey`, and `~~>globalKey` patterns.
101
203
  - **Conditional execution**: Supports the same condition system as actions (`when`, `is`, `isEmpty`, `isNotEmpty`, etc.).
204
+ - **Undefined handling**: `undefined` values are ignored in append mode but assigned in replace mode.
@@ -12,16 +12,23 @@ renderView:
12
12
  - type: TabbedSerializer
13
13
  yamlSerializedContent: |
14
14
  attributeTransforms:
15
- # Add CSS class
15
+ # Add CSS class (string mode)
16
16
  - what: setAttributeValue
17
17
  name: "class"
18
18
  value: "active"
19
19
 
20
- # Replace attribute value
20
+ # Replace attribute value (string mode)
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: "var(--bs-secondary-bg-subtle, rgba(0, 0, 0, 0.05))"
25
32
 
26
33
  - type: Markdown
27
34
  content: |
@@ -44,8 +51,14 @@ renderView:
44
51
  - `"replace"`: Completely replaces the existing attribute value
45
52
  - term:
46
53
  code: value
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.
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.
49
62
  - term:
50
63
  code: preventDuplicateValues
51
64
  after: "(boolean, optional)"
@@ -65,16 +78,36 @@ renderView:
65
78
 
66
79
  ## Behavior
67
80
 
81
+ The transformer operates in two distinct modes based on the `value` type:
82
+
83
+ ### String Mode (when `value` is a string)
84
+
68
85
  - **Append mode**: Adds the new value to the existing attribute, separated by the specified separator.
69
86
  - **Replace mode**: Completely overwrites the existing attribute value.
70
87
  - **Duplicate prevention**: In append mode, prevents adding duplicate values when enabled.
71
88
 
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
+
72
105
  ## Common Use Cases
73
106
 
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.
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.
78
111
 
79
112
  - type: RjBuildDescriber
80
113
  title: "SetAttributeValue Action Examples"
@@ -108,6 +141,8 @@ renderView:
108
141
  margin: "10px 0"
109
142
  width: "300px"
110
143
  display: "block"
144
+ backgroundColor: "var(--bs-secondary-bg-subtle, rgba(0, 0, 0, 0.05))"
145
+ color: "#212529"
111
146
  actions:
112
147
  - what: setData
113
148
  on: change
@@ -134,11 +169,108 @@ renderView:
134
169
  data:
135
170
  input_data: ""
136
171
 
172
+ - type: RjBuildDescriber
173
+ title: "Object Mode Example - Style Merging"
174
+ description:
175
+ - type: Markdown
176
+ content: |
177
+ This example demonstrates how to use `setAttributeValue` in object mode to merge style properties without losing existing ones.
178
+
179
+ **Expected behavior:**
180
+ - The div has initial styles (padding, border, borderRadius)
181
+ - When `isHighlighted` is true, additional style properties are merged
182
+ - The modification changes the highlight color for vertical borders (left and right), as `borderColor` contains two colors
183
+ - The original styles are preserved, and new properties are added
184
+ - Try toggling the highlight to see the style merge in action
185
+
186
+ toDescribe:
187
+ renderView:
188
+ - type: div
189
+ attributes:
190
+ style:
191
+ padding: "10px"
192
+ borderWidth: "5px"
193
+ borderStyle: "solid"
194
+ borderColor: "black"
195
+ borderRadius: "4px"
196
+ backgroundColor: "var(--bs-secondary-bg-subtle, rgba(0, 0, 0, 0.05))"
197
+ color: "#212529"
198
+ attributeTransforms:
199
+ # Merge additional style properties without losing existing ones
200
+ - what: setAttributeValue
201
+ name: "style"
202
+ value:
203
+ borderColor: "var(--bs-primary, #3b82f6)"
204
+ when: ~.isHighlighted
205
+ is: true
206
+ content: "Click to toggle highlight"
207
+
208
+ - type: button
209
+ content: "Toggle Highlight"
210
+ actions:
211
+ - what: setData
212
+ on: click
213
+ path: ~.isHighlighted
214
+ value: true
215
+ when: ~.isHighlighted
216
+ is: false
217
+ - what: setData
218
+ on: click
219
+ path: ~.isHighlighted
220
+ value: false
221
+ when: ~.isHighlighted
222
+ is: true
223
+
224
+ data:
225
+ isHighlighted: false
226
+
227
+ - type: RjBuildDescriber
228
+ title: "Object Mode Replace Example"
229
+ description:
230
+ - type: Markdown
231
+ content: |
232
+ This example demonstrates how to completely replace a style object using `mode: "replace"`.
233
+
234
+ **Expected behavior:**
235
+ - The div has initial styles (padding, border)
236
+ - When replace mode is used, the entire style object is replaced
237
+ - Original styles are lost, only the new styles remain
238
+
239
+ toDescribe:
240
+ renderView:
241
+ - type: div
242
+ attributes:
243
+ style:
244
+ padding: "10px"
245
+ border: "2px solid #007bff"
246
+ backgroundColor: "var(--bs-secondary-bg-subtle, rgba(0, 0, 0, 0.05))"
247
+ color: "#212529"
248
+ attributeTransforms:
249
+ # Completely replace the style object
250
+ - what: setAttributeValue
251
+ name: "style"
252
+ mode: "replace"
253
+ value:
254
+ backgroundColor: "var(--bs-primary-bg-subtle, #d4f0ec)"
255
+ color: "var(--bs-primary-text-emphasis, #2b6b5a)"
256
+ padding: "15px"
257
+ borderRadius: "8px"
258
+ border: "2px solid var(--bs-primary, #44a08d)"
259
+ content: "This div's style was completely replaced"
260
+
137
261
  - type: Markdown
138
262
  content: |
139
263
  ## Notes
140
264
 
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.
265
+ - **Pre-render execution**: This transformer modifies attributes before the component renders, ensuring child components receive the transformed attributes.
266
+ - **Mode detection**: The transformer automatically detects whether to use string mode or object mode based on the `value` type after template evaluation.
267
+ - **Append mode behavior**:
268
+ - **String mode**: Respects existing attribute values, adding new values separated by the specified separator.
269
+ - **Object mode**: Merges properties property by property, applying string append logic where both values are strings, otherwise replacing with the new value.
270
+ - **Replace mode**: Use when you need complete control over the attribute value. In object mode, completely replaces the entire object.
271
+ - **Duplicate prevention**: Only applies to append mode, and works for string values in both string mode and object mode.
272
+ - **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).
273
+ - **Extended properties vs shorthand**: When transformations are required, prefer using extended CSS properties (e.g., `borderWidth`, `borderStyle`, `borderColor`) instead of shorthand properties (e.g., `border`). This ensures the browser handles property modifications correctly. When you modify a single property like `borderColor` on an element that uses the shorthand `border`, the browser may decompose the shorthand into individual properties, which can lead to unexpected behavior. Using extended properties from the start avoids this issue.
274
+ - **Template evaluation**: The value property supports full template evaluation including `~.localData`, `~~.globalData`, `~>nearestKey`, and `~~>globalKey` patterns.
275
+ - **Conditional execution**: Supports the same condition system as actions (`when`, `is`, `isEmpty`, `isNotEmpty`, etc.).
276
+ - **Undefined handling**: `undefined` values are ignored in append mode but assigned in replace mode.
@@ -0,0 +1,211 @@
1
+ # DataFilter Example: Filtering Direct Array Items
2
+
3
+ This example demonstrates how to use `DataFilter` with arrays where each item is a direct object (not wrapped in a namespace property). This is useful when working with data from APIs that return arrays of objects directly.
4
+
5
+ ## Use Case
6
+
7
+ When your data structure is a direct array of objects like:
8
+ ```yaml
9
+ data:
10
+ rows:
11
+ - id: 1
12
+ label: "Operation 1"
13
+ done: "done"
14
+ operation: "create"
15
+ - id: 2
16
+ label: "Operation 2"
17
+ done: "pending"
18
+ operation: "update"
19
+ ```
20
+
21
+ Instead of:
22
+ ```yaml
23
+ data:
24
+ rows:
25
+ - item:
26
+ id: 1
27
+ label: "Operation 1"
28
+ ```
29
+
30
+ ## Solution
31
+
32
+ Use an existing property that is present in all items (like `id`) as the `subjectsWithProperty` namespace. In `whenFilterableData`, reference properties directly without the namespace prefix.
33
+
34
+ **Important**: When using string values for filtering (like status), use a special value like `"all"` to represent "no filter" instead of an empty string, as empty strings can cause issues with select elements.
35
+
36
+ ## Complete Example
37
+
38
+ ```yaml
39
+ renderView:
40
+ - type: DataFilter
41
+ context: global
42
+ filters:
43
+ - subjectsWithProperty: id
44
+ andConditions:
45
+ # Filter by status (string)
46
+ - orConditions:
47
+ - when: ~~._filters.done
48
+ is: "all"
49
+ - whenFilterableData: done
50
+ is: ~~._filters.done
51
+
52
+ # Filter by operation type (text search with contains)
53
+ - orConditions:
54
+ - when: ~~._filters.operation
55
+ is: ""
56
+ - andConditions:
57
+ - whenFilterableData: operation
58
+ isNotEmpty: true
59
+ - when: ~~._filters.operation
60
+ isNotEmpty: true
61
+ - whenFilterableData: operation
62
+ contains: ~~._filters.operation
63
+
64
+ # Filter by label (text search with contains)
65
+ - orConditions:
66
+ - when: ~~._filters.label
67
+ is: ""
68
+ - andConditions:
69
+ - whenFilterableData: label
70
+ isNotEmpty: true
71
+ - when: ~~._filters.label
72
+ isNotEmpty: true
73
+ - whenFilterableData: label
74
+ contains: ~~._filters.label
75
+ content:
76
+ - type: Switch
77
+ content: ~~.rows
78
+ singleOption:
79
+ load: operationRow
80
+
81
+ templates:
82
+ operationRow:
83
+ - type: tr
84
+ content:
85
+ - type: td
86
+ content: ~.id
87
+ - type: td
88
+ content: ~.label
89
+ - type: td
90
+ content: ~.done
91
+ - type: td
92
+ content: ~.operation
93
+
94
+ data:
95
+ rows:
96
+ - id: 1
97
+ label: "Operation 1"
98
+ done: "done"
99
+ operation: "create"
100
+ - id: 2
101
+ label: "Operation 2"
102
+ done: "pending"
103
+ operation: "update"
104
+ - id: 3
105
+ label: "Operation 3"
106
+ done: "done"
107
+ operation: "create"
108
+ _filters:
109
+ done: "all"
110
+ label: ""
111
+ operation: ""
112
+ ```
113
+
114
+ ## Key Points
115
+
116
+ 1. **Namespace Selection**: Choose a property that exists in all items (e.g., `id`, `name`, `key`). This property acts as the identifier for DataFilter to recognize filterable items.
117
+
118
+ 2. **Direct Property Access**: In `whenFilterableData`, reference properties directly:
119
+ - ✅ `whenFilterableData: label` (correct)
120
+ - ❌ `whenFilterableData: id.label` (incorrect - don't use namespace prefix)
121
+
122
+ 3. **String-based Filtering**: When using select elements for filtering, use a special value like `"all"` to represent "no filter" instead of an empty string:
123
+ ```yaml
124
+ - orConditions:
125
+ - when: ~~._filters.done
126
+ is: "all" # Shows all items
127
+ - whenFilterableData: done
128
+ is: ~~._filters.done # Filters by exact match
129
+ ```
130
+ This avoids issues where select elements might not properly handle empty string values.
131
+
132
+ 4. **Text Search**: For text search with `contains`, ensure both the filter value and the data property are not empty:
133
+ ```yaml
134
+ - orConditions:
135
+ - when: ~~._filters.label
136
+ is: "" # Shows all when empty
137
+ - andConditions:
138
+ - whenFilterableData: label
139
+ isNotEmpty: true
140
+ - when: ~~._filters.label
141
+ isNotEmpty: true
142
+ - whenFilterableData: label
143
+ contains: ~~._filters.label
144
+ ```
145
+ The `andConditions` wrapper ensures that both the data property and filter value are not empty before attempting the `contains` comparison.
146
+
147
+ 5. **Template Access**: In templates, access properties directly without namespace:
148
+ - ✅ `~.label`, `~.done`, `~.operation`
149
+ - ❌ `~.id.label` (incorrect)
150
+
151
+ ## Filter Types Demonstrated
152
+
153
+ - **Select Filter with "All" option**: Using `is: "all"` to show all items when a special "all" value is selected
154
+ - **Exact String Match**: Using `is` for exact string matching (e.g., status filtering)
155
+ - **Text Search**: Using `contains` for substring matching (case-insensitive) with proper empty checks
156
+
157
+ ## Additional Template Techniques
158
+
159
+ **Conditional Display in Templates**: The example uses `hide` actions to conditionally display badges based on data values. This is a common pattern for showing different UI elements based on data state:
160
+
161
+ ```yaml
162
+ - type: span
163
+ content: "Done"
164
+ actions:
165
+ - what: hide
166
+ when: ~.done
167
+ isNot: "done" # Hide if status is not "done"
168
+ - type: span
169
+ content: "Pending"
170
+ actions:
171
+ - what: hide
172
+ when: ~.done
173
+ isNot: "pending" # Hide if status is not "pending"
174
+ ```
175
+
176
+ This technique is used in the example to display colored status badges, but it's not part of the DataFilter pattern itself - it's just a way to enhance the visual display of filtered data.
177
+
178
+ ## Filter Patterns
179
+
180
+ ### Pattern 1: Select Filter with "All" Option
181
+ ```yaml
182
+ - orConditions:
183
+ - when: ~~._filters.status
184
+ is: "all" # Special value for "show all"
185
+ - whenFilterableData: status
186
+ is: ~~._filters.status # Exact match filter
187
+ ```
188
+
189
+ ### Pattern 2: Text Input Filter (Empty String Check)
190
+ ```yaml
191
+ - orConditions:
192
+ - when: ~~._filters.search
193
+ is: "" # Empty string means "show all"
194
+ - andConditions:
195
+ - whenFilterableData: searchField
196
+ isNotEmpty: true
197
+ - when: ~~._filters.search
198
+ isNotEmpty: true
199
+ - whenFilterableData: searchField
200
+ contains: ~~._filters.search
201
+ ```
202
+
203
+ ## Notes
204
+
205
+ - The `subjectsWithProperty` value (`id` in this example) must exist in every item of the array
206
+ - DataFilter filters the data before rendering, so no `hide` actions are needed in templates
207
+ - All filter conditions use `orConditions` with an empty/"all" check first, allowing "show all" when filters are empty or set to "all"
208
+ - For select elements, prefer using a special value like `"all"` instead of empty strings to avoid UI issues
209
+ - For text inputs, empty strings (`""`) work fine for the "show all" condition
210
+ - When using `contains` for text search, always wrap the condition in `andConditions` with `isNotEmpty` checks to avoid errors with empty values
211
+