vident 1.0.0.alpha1 → 1.0.0.alpha3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -1
- data/README.md +51 -17
- data/lib/vident/class_list_builder.rb +13 -2
- data/lib/vident/component.rb +15 -10
- data/lib/vident/component_attribute_resolver.rb +33 -8
- data/lib/vident/component_class_lists.rb +5 -3
- data/lib/vident/stimulus_attributes.rb +4 -3
- data/lib/vident/stimulus_builder.rb +34 -11
- data/lib/vident/{stimulus_dsl.rb → stimulus_helper.rb} +7 -7
- data/lib/vident/version.rb +1 -1
- data/lib/vident.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ae2c093011a8047255f21fff2b284520d9be75660af61afc511c85bfdcc9f76
|
4
|
+
data.tar.gz: 47bbde103e62632fca8a11bb1ddd6321dd8c6c8711d21790a51a3e657e3d6f66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df35e4be8597d580ad4f50b63f99c1e0a8032fd52c9c06676b6d4db9ee15a781f80d00c5112c87047238361560b5a131e60f11800e07c03f904d1e781fed3312
|
7
|
+
data.tar.gz: 5794832b1bb4a4abbc532beabdbe9133c3a45b7ef42eca8d11660051466a7b64298af3bcb8c7c90c55381a25bfec0680afe389f319c2b8ffc1602f1fb3f47d16
|
data/CHANGELOG.md
CHANGED
@@ -5,7 +5,25 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
7
7
|
|
8
|
-
## [1.0.0.
|
8
|
+
## [1.0.0.alpha3] - 2025-07-21
|
9
|
+
|
10
|
+
### Breaking
|
11
|
+
- `element_classes` is now `root_element_classes` to make more consistent with the other root element methods.
|
12
|
+
|
13
|
+
### Added
|
14
|
+
|
15
|
+
-`.prop_names` and `#prop_values` methods to `Vident::Component` to return the names and values of the component's properties.
|
16
|
+
|
17
|
+
## [1.0.0.alpha2] - 2025-07-08
|
18
|
+
|
19
|
+
### Breaking
|
20
|
+
- `nil` values in Stimulus values are ok, but `nil` for an action/target/outlet makes no sense so is ignored.
|
21
|
+
|
22
|
+
### Fixed
|
23
|
+
|
24
|
+
- `stimulus_scoped_event` must return a Symbol to work with `stimulus_action` and `stimulus_target` methods etc.
|
25
|
+
|
26
|
+
## [1.0.0.alpha1] - 2025-07-08
|
9
27
|
|
10
28
|
This release is a major overhaul of the Vident library, and introduces a new API for defining components and Stimulus attributes. The new API is designed to be more consistent and easier to use.
|
11
29
|
|
data/README.md
CHANGED
@@ -76,27 +76,32 @@ class ButtonComponent < Vident::ViewComponent::Base
|
|
76
76
|
|
77
77
|
# Configure Stimulus integration
|
78
78
|
stimulus do
|
79
|
-
actions
|
80
|
-
|
81
|
-
|
79
|
+
# Setup actions, including with proc to evaluate on instance
|
80
|
+
actions [:click, :handle_click],
|
81
|
+
-> { [stimulus_scoped_event(:my_custom_event), :handle_this] if should_handle_this? }
|
82
82
|
# Map the clicked_count prop as a Stimulus value
|
83
83
|
values_from_props :clicked_count
|
84
84
|
# Dynamic values using procs (evaluated in component context)
|
85
|
-
values item_count: -> { @items.count }
|
86
|
-
|
85
|
+
values item_count: -> { @items.count },
|
86
|
+
api_url: -> { Rails.application.routes.url_helpers.api_items_path },
|
87
|
+
loading_duration: 1000 # or set static values
|
87
88
|
# Static and dynamic classes
|
88
|
-
classes loading: "opacity-50 cursor-wait"
|
89
|
-
|
89
|
+
classes loading: "opacity-50 cursor-wait",
|
90
|
+
size: -> { @items.count > 10 ? "large" : "small" }
|
90
91
|
end
|
91
92
|
|
92
93
|
def call
|
93
|
-
root_element do
|
94
|
-
|
94
|
+
root_element do |component|
|
95
|
+
# Wire up targets etc
|
96
|
+
component.tag(:span, stimulus_target: :status) do
|
97
|
+
@text
|
98
|
+
end
|
95
99
|
end
|
96
100
|
end
|
97
101
|
|
98
102
|
private
|
99
103
|
|
104
|
+
# Configure your components root HTML element
|
100
105
|
def root_element_attributes
|
101
106
|
{
|
102
107
|
element_tag: @url ? :a : :button,
|
@@ -104,7 +109,8 @@ class ButtonComponent < Vident::ViewComponent::Base
|
|
104
109
|
}
|
105
110
|
end
|
106
111
|
|
107
|
-
|
112
|
+
# optionally add logic to determine initial classes
|
113
|
+
def root_element_classes
|
108
114
|
base_classes = "btn"
|
109
115
|
case @style
|
110
116
|
when :primary
|
@@ -130,14 +136,19 @@ export default class extends Controller {
|
|
130
136
|
loadingDuration: Number
|
131
137
|
}
|
132
138
|
static classes = ["loading"]
|
139
|
+
static targets = ["status"]
|
133
140
|
|
134
141
|
handleClick(event) {
|
135
142
|
// Increment counter
|
136
143
|
this.clickedCountValue++
|
137
144
|
|
145
|
+
// Store original text
|
146
|
+
const originalText = this.statusTarget.textContent
|
147
|
+
|
138
148
|
// Add loading state
|
139
149
|
this.element.classList.add(this.loadingClass)
|
140
150
|
this.element.disabled = true
|
151
|
+
this.statusTarget.textContent = "Loading..."
|
141
152
|
|
142
153
|
// Use the loading duration from the component
|
143
154
|
setTimeout(() => {
|
@@ -145,7 +156,7 @@ export default class extends Controller {
|
|
145
156
|
this.element.disabled = false
|
146
157
|
|
147
158
|
// Update text to show count
|
148
|
-
this.
|
159
|
+
this.statusTarget.textContent = `${originalText} (${this.clickedCountValue})`
|
149
160
|
}, this.loadingDurationValue)
|
150
161
|
}
|
151
162
|
}
|
@@ -178,7 +189,7 @@ The rendered HTML includes all Stimulus data attributes:
|
|
178
189
|
data-button-component-loading-duration-value="1000"
|
179
190
|
data-button-component-loading-class="opacity-50 cursor-wait"
|
180
191
|
id="button-component-123">
|
181
|
-
Save
|
192
|
+
<span data-button-component-target="status">Save</span>
|
182
193
|
</button>
|
183
194
|
|
184
195
|
<!-- Second button with pre-set count -->
|
@@ -189,7 +200,7 @@ The rendered HTML includes all Stimulus data attributes:
|
|
189
200
|
data-button-component-loading-duration-value="1000"
|
190
201
|
data-button-component-loading-class="opacity-50 cursor-wait"
|
191
202
|
id="button-component-456">
|
192
|
-
Submit
|
203
|
+
<span data-button-component-target="status">Submit</span>
|
193
204
|
</button>
|
194
205
|
```
|
195
206
|
|
@@ -218,6 +229,29 @@ class CardComponent < Vident::ViewComponent::Base
|
|
218
229
|
end
|
219
230
|
```
|
220
231
|
|
232
|
+
### Post-Initialization Hooks
|
233
|
+
|
234
|
+
Vident provides a hook for performing actions after component initialization:
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
class MyComponent < Vident::ViewComponent::Base
|
238
|
+
prop :data, Hash, default: -> { {} }
|
239
|
+
|
240
|
+
def after_component_initialize
|
241
|
+
@processed_data = process_data(@data)
|
242
|
+
end
|
243
|
+
|
244
|
+
private
|
245
|
+
|
246
|
+
def process_data(data)
|
247
|
+
# Your initialization logic here
|
248
|
+
data.transform_values(&:upcase)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
**Important**: If you decide to override Literal's `after_initialize`, you **must** call `super` first to ensure Vident's initialization completes properly. Alternatively, use `after_component_initialize` which doesn't require calling `super`.
|
254
|
+
|
221
255
|
### Built-in Properties
|
222
256
|
|
223
257
|
Every Vident component includes these properties:
|
@@ -233,7 +267,7 @@ The `root_element` helper method renders your component's root element with all
|
|
233
267
|
|
234
268
|
```ruby
|
235
269
|
# In your component class
|
236
|
-
def
|
270
|
+
def root_element_classes
|
237
271
|
["card", featured? ? "card-featured" : nil]
|
238
272
|
end
|
239
273
|
|
@@ -389,7 +423,7 @@ Vident provides helper methods to generate scoped event names for dispatching cu
|
|
389
423
|
class MyComponent < Vident::ViewComponent::Base
|
390
424
|
stimulus do
|
391
425
|
# Define an action that responds to a scoped event
|
392
|
-
actions [stimulus_scoped_event_on_window(:data_loaded), :handle_data_loaded]
|
426
|
+
actions -> { [stimulus_scoped_event_on_window(:data_loaded), :handle_data_loaded] }
|
393
427
|
end
|
394
428
|
|
395
429
|
def handle_click
|
@@ -589,7 +623,7 @@ class StyledComponent < Vident::ViewComponent::Base
|
|
589
623
|
private
|
590
624
|
|
591
625
|
# Classes on the root element
|
592
|
-
def
|
626
|
+
def root_element_classes
|
593
627
|
["base-class", variant_class]
|
594
628
|
end
|
595
629
|
|
@@ -623,7 +657,7 @@ class TailwindComponent < Vident::ViewComponent::Base
|
|
623
657
|
|
624
658
|
private
|
625
659
|
|
626
|
-
def
|
660
|
+
def root_element_classes
|
627
661
|
# Conflicts with size_class will be resolved automatically
|
628
662
|
"p-2 text-sm #{size_class}"
|
629
663
|
end
|
@@ -6,12 +6,23 @@ module Vident
|
|
6
6
|
class ClassListBuilder
|
7
7
|
CLASSNAME_SEPARATOR = " "
|
8
8
|
|
9
|
-
|
9
|
+
# If the HTML "class" option is provided, it is taken in order of precedence of source.
|
10
|
+
# The order of precedence is:
|
11
|
+
# lowest | root_element_classes => whatever is returned
|
12
|
+
# ....... | root_element_attributes => the `html_options[:class]` value
|
13
|
+
# ....... | root_element(class: ...) => the `class` value of the arguments passed to the root element
|
14
|
+
# highest | render MyComponent.new(html_options: { class: ... }) => the `html_options[:class]` value
|
15
|
+
# The "classes" prop on the component on the other hand is used to add additional classes to the component.
|
16
|
+
# eg: render MyComponent.new(classes: "my-additional-class another-class")
|
17
|
+
def initialize(tailwind_merger: nil, component_name: nil, root_element_attributes_classes: nil, root_element_classes: nil, root_element_html_class: nil, html_class: nil, additional_classes: nil)
|
10
18
|
@class_list = component_name ? [component_name] : []
|
11
|
-
@class_list.concat(Array.wrap(
|
19
|
+
@class_list.concat(Array.wrap(root_element_classes)) if root_element_classes && !root_element_attributes_classes && !root_element_html_class && !html_class
|
20
|
+
@class_list.concat(Array.wrap(root_element_attributes_classes)) if root_element_attributes_classes && !root_element_html_class && !html_class
|
21
|
+
@class_list.concat(Array.wrap(root_element_html_class)) if root_element_html_class && !html_class
|
12
22
|
@class_list.concat(Array.wrap(html_class)) if html_class
|
13
23
|
@class_list.concat(Array.wrap(additional_classes)) if additional_classes
|
14
24
|
@class_list.compact!
|
25
|
+
|
15
26
|
@tailwind_merger = tailwind_merger
|
16
27
|
|
17
28
|
if @tailwind_merger && !defined?(::TailwindMerge::Merger)
|
data/lib/vident/component.rb
CHANGED
@@ -16,20 +16,27 @@ module Vident
|
|
16
16
|
prop :html_options, Hash, default: -> { {} }
|
17
17
|
end
|
18
18
|
|
19
|
+
class_methods do
|
20
|
+
# Returns the names of the properties defined in the component class.
|
21
|
+
def prop_names
|
22
|
+
literal_properties.properties_index.keys.map(&:to_sym)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
19
26
|
include StimulusComponent
|
20
27
|
include ComponentClassLists
|
21
28
|
include ComponentAttributeResolver
|
22
29
|
|
23
30
|
include TagHelper
|
24
31
|
include Tailwind
|
25
|
-
include
|
32
|
+
include StimulusHelper
|
26
33
|
|
27
34
|
# Override this method to perform any initialisation after attributes are set
|
28
35
|
def after_component_initialize
|
29
36
|
end
|
30
37
|
|
31
38
|
# This can be overridden to return an array of extra class names, or a string of class names.
|
32
|
-
def
|
39
|
+
def root_element_classes
|
33
40
|
end
|
34
41
|
|
35
42
|
# Properties/attributes passed to the "root" element of the component. You normally override this method to
|
@@ -50,6 +57,12 @@ module Vident
|
|
50
57
|
# attributes which require elements to reference by ID. Note this overrides the `id` accessor
|
51
58
|
def id = @id.presence || random_id
|
52
59
|
|
60
|
+
|
61
|
+
# Return the names of the properties defined in the component class.
|
62
|
+
def prop_names
|
63
|
+
self.class.prop_names
|
64
|
+
end
|
65
|
+
|
53
66
|
private
|
54
67
|
|
55
68
|
# Called by Literal::Properties after the component is initialized.
|
@@ -66,14 +79,6 @@ module Vident
|
|
66
79
|
root_element(...)
|
67
80
|
end
|
68
81
|
|
69
|
-
def root_element_tag_options
|
70
|
-
options = @html_options&.dup || {}
|
71
|
-
data_attrs = stimulus_data_attributes
|
72
|
-
options[:data] = options[:data].present? ? data_attrs.merge(options[:data]) : data_attrs
|
73
|
-
return options unless @id
|
74
|
-
options.merge(id: @id)
|
75
|
-
end
|
76
|
-
|
77
82
|
def root_element_tag_type
|
78
83
|
@element_tag.presence&.to_sym || :div
|
79
84
|
end
|
@@ -4,18 +4,18 @@ module Vident
|
|
4
4
|
module ComponentAttributeResolver
|
5
5
|
private
|
6
6
|
|
7
|
-
#
|
7
|
+
# Prepare attributes set at initialization, which will later be merged together before rendering.
|
8
8
|
def prepare_component_attributes
|
9
9
|
prepare_stimulus_collections
|
10
10
|
|
11
11
|
# Add stimulus attributes from DSL first (lower precedence)
|
12
12
|
add_stimulus_attributes_from_dsl
|
13
13
|
|
14
|
-
# Process root_element_attributes (higher precedence)
|
14
|
+
# Process root_element_attributes (higher precedence)
|
15
15
|
extra = root_element_attributes
|
16
16
|
@html_options = (extra[:html_options] || {}).merge(@html_options) if extra.key?(:html_options)
|
17
|
-
@
|
18
|
-
@
|
17
|
+
@root_element_attributes_classes = extra[:classes]
|
18
|
+
@root_element_attributes_id = (extra[:id] || id)
|
19
19
|
@element_tag = extra[:element_tag] if extra.key?(:element_tag)
|
20
20
|
|
21
21
|
add_stimulus_controllers(extra[:stimulus_controllers]) if extra.key?(:stimulus_controllers)
|
@@ -26,6 +26,32 @@ module Vident
|
|
26
26
|
add_stimulus_classes(extra[:stimulus_classes]) if extra.key?(:stimulus_classes)
|
27
27
|
end
|
28
28
|
|
29
|
+
def resolve_root_element_attributes_before_render(root_element_html_options = nil)
|
30
|
+
extra = root_element_html_options || {}
|
31
|
+
|
32
|
+
# Options set on component at render time take precedence over attributes set by methods on the component
|
33
|
+
# or attributes passed to root_element in the template
|
34
|
+
final_attributes = {
|
35
|
+
data: stimulus_data_attributes # Lowest precedence
|
36
|
+
}
|
37
|
+
if root_element_html_options.present? # Mid precedence
|
38
|
+
root_element_tag_html_options_merge(final_attributes, root_element_html_options)
|
39
|
+
end
|
40
|
+
if @html_options.present? # Highest precedence
|
41
|
+
root_element_tag_html_options_merge(final_attributes, @html_options)
|
42
|
+
end
|
43
|
+
final_attributes[:class] = render_classes(extra[:class])
|
44
|
+
final_attributes[:id] = (extra[:id] || @root_element_attributes_id) unless final_attributes.key?(:id)
|
45
|
+
final_attributes
|
46
|
+
end
|
47
|
+
|
48
|
+
def root_element_tag_html_options_merge(final_attributes, other_html_options)
|
49
|
+
if other_html_options[:data].present?
|
50
|
+
final_attributes[:data].merge!(other_html_options[:data])
|
51
|
+
end
|
52
|
+
final_attributes.merge!(other_html_options.except(:data))
|
53
|
+
end
|
54
|
+
|
29
55
|
# Add stimulus attributes from DSL declarations using existing add_* methods
|
30
56
|
def add_stimulus_attributes_from_dsl
|
31
57
|
dsl_attrs = self.class.stimulus_dsl_attributes(self)
|
@@ -36,20 +62,19 @@ module Vident
|
|
36
62
|
add_stimulus_actions(dsl_attrs[:stimulus_actions]) if dsl_attrs[:stimulus_actions]
|
37
63
|
add_stimulus_targets(dsl_attrs[:stimulus_targets]) if dsl_attrs[:stimulus_targets]
|
38
64
|
add_stimulus_outlets(dsl_attrs[:stimulus_outlets]) if dsl_attrs[:stimulus_outlets]
|
39
|
-
|
65
|
+
|
40
66
|
# Add static values (now includes resolved proc values)
|
41
67
|
add_stimulus_values(dsl_attrs[:stimulus_values]) if dsl_attrs[:stimulus_values]
|
42
|
-
|
68
|
+
|
43
69
|
# Resolve and add values from props
|
44
70
|
if dsl_attrs[:stimulus_values_from_props]
|
45
71
|
resolved_values = resolve_values_from_props(dsl_attrs[:stimulus_values_from_props])
|
46
72
|
add_stimulus_values(resolved_values) unless resolved_values.empty?
|
47
73
|
end
|
48
|
-
|
74
|
+
|
49
75
|
add_stimulus_classes(dsl_attrs[:stimulus_classes]) if dsl_attrs[:stimulus_classes]
|
50
76
|
end
|
51
77
|
|
52
|
-
|
53
78
|
# Prepare stimulus collections and implied controller path from the given attributes, called after initialization
|
54
79
|
def prepare_stimulus_collections # Convert raw attributes to stimulus attribute collections
|
55
80
|
@stimulus_controllers_collection = stimulus_controllers(*Array.wrap(@stimulus_controllers))
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Vident
|
4
4
|
module ComponentClassLists
|
5
5
|
# Generates the full list of HTML classes for the component
|
6
|
-
def render_classes(
|
6
|
+
def render_classes(root_element_html_class = nil) = class_list_builder(root_element_html_class).build
|
7
7
|
|
8
8
|
# Getter for a stimulus classes list so can be used in view to set initial state on SSR
|
9
9
|
# Returns a String of classes that can be used in a `class` attribute.
|
@@ -15,11 +15,13 @@ module Vident
|
|
15
15
|
|
16
16
|
# Get or create a class list builder instance
|
17
17
|
# Automatically detects if Tailwind module is included and TailwindMerge gem is available
|
18
|
-
def class_list_builder
|
18
|
+
def class_list_builder(root_element_html_class = nil)
|
19
19
|
@class_list_builder ||= ClassListBuilder.new(
|
20
20
|
tailwind_merger:,
|
21
21
|
component_name:,
|
22
|
-
|
22
|
+
root_element_attributes_classes: @root_element_attributes_classes,
|
23
|
+
root_element_classes:,
|
24
|
+
root_element_html_class:,
|
23
25
|
additional_classes: @classes,
|
24
26
|
html_class: @html_options&.fetch(:class, nil)
|
25
27
|
)
|
@@ -5,13 +5,14 @@ module Vident
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
class_methods do
|
8
|
-
# Class methods for generating scoped event names
|
8
|
+
# Class methods for generating scoped event names. Returns a symbol
|
9
|
+
# so that the action parser will see it as a Stimulus event.
|
9
10
|
def stimulus_scoped_event(event)
|
10
|
-
"#{component_name}:#{stimulus_js_name(event)}"
|
11
|
+
:"#{component_name}:#{stimulus_js_name(event)}"
|
11
12
|
end
|
12
13
|
|
13
14
|
def stimulus_scoped_event_on_window(event)
|
14
|
-
"#{component_name}:#{stimulus_js_name(event)}@window"
|
15
|
+
:"#{component_name}:#{stimulus_js_name(event)}@window"
|
15
16
|
end
|
16
17
|
|
17
18
|
private
|
@@ -35,7 +35,7 @@ module Vident
|
|
35
35
|
@values.merge!(value_hash) unless value_hash.empty?
|
36
36
|
self
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def values_from_props(*prop_names)
|
40
40
|
@values_from_props.concat(prop_names)
|
41
41
|
self
|
@@ -53,11 +53,11 @@ module Vident
|
|
53
53
|
|
54
54
|
def to_attributes(component_instance)
|
55
55
|
attrs = {}
|
56
|
-
attrs[:stimulus_actions] =
|
57
|
-
attrs[:stimulus_targets] =
|
58
|
-
attrs[:stimulus_values] =
|
56
|
+
attrs[:stimulus_actions] = resolve_attributes_filtering_nil(@actions, component_instance) unless @actions.empty?
|
57
|
+
attrs[:stimulus_targets] = resolve_attributes_filtering_nil(@targets, component_instance) unless @targets.empty?
|
58
|
+
attrs[:stimulus_values] = resolve_hash_values_allowing_nil(@values, component_instance) unless @values.empty?
|
59
59
|
attrs[:stimulus_values_from_props] = @values_from_props.dup unless @values_from_props.empty?
|
60
|
-
attrs[:stimulus_classes] =
|
60
|
+
attrs[:stimulus_classes] = resolve_hash_classes_filtering_nil(@classes, component_instance) unless @classes.empty?
|
61
61
|
attrs[:stimulus_outlets] = @outlets.dup unless @outlets.empty?
|
62
62
|
attrs
|
63
63
|
end
|
@@ -95,22 +95,45 @@ module Vident
|
|
95
95
|
|
96
96
|
private
|
97
97
|
|
98
|
-
|
99
|
-
|
98
|
+
# For actions, targets - filter out nil values from procs AND static
|
99
|
+
def resolve_attributes_filtering_nil(array, component_instance)
|
100
|
+
result = []
|
101
|
+
array.each do |value|
|
100
102
|
if callable?(value)
|
101
|
-
component_instance.instance_exec(&value)
|
103
|
+
resolved_value = component_instance.instance_exec(&value)
|
104
|
+
# Exclude nil from procs (nil is not valid for actions/targets)
|
105
|
+
result << resolved_value unless resolved_value.nil?
|
102
106
|
else
|
103
|
-
|
107
|
+
# Exclude static nil values (nil is not valid for actions/targets)
|
108
|
+
result << value unless value.nil?
|
104
109
|
end
|
105
110
|
end
|
111
|
+
result
|
106
112
|
end
|
107
113
|
|
108
|
-
|
114
|
+
# For values - allow nil values from procs and static (will become "null" in JavaScript)
|
115
|
+
def resolve_hash_values_allowing_nil(hash, component_instance)
|
109
116
|
hash.transform_values { |value| callable?(value) ? component_instance.instance_exec(&value) : value }
|
110
117
|
end
|
111
118
|
|
119
|
+
# For classes - filter out nil values from procs AND static
|
120
|
+
def resolve_hash_classes_filtering_nil(hash, component_instance)
|
121
|
+
result = {}
|
122
|
+
hash.each do |key, value|
|
123
|
+
if callable?(value)
|
124
|
+
resolved_value = component_instance.instance_exec(&value)
|
125
|
+
# Exclude nil from procs (nil is not valid for classes)
|
126
|
+
result[key] = resolved_value unless resolved_value.nil?
|
127
|
+
else
|
128
|
+
# Exclude static nil values (nil is not valid for classes)
|
129
|
+
result[key] = value unless value.nil?
|
130
|
+
end
|
131
|
+
end
|
132
|
+
result
|
133
|
+
end
|
134
|
+
|
112
135
|
def callable?(value)
|
113
136
|
value.respond_to?(:call)
|
114
137
|
end
|
115
138
|
end
|
116
|
-
end
|
139
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Vident
|
4
|
-
module
|
4
|
+
module StimulusHelper
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
class_methods do
|
@@ -11,10 +11,10 @@ module Vident
|
|
11
11
|
@stimulus_builder = StimulusBuilder.new
|
12
12
|
@inheritance_merged = false
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
# Ensure inheritance is applied
|
16
16
|
ensure_inheritance_merged
|
17
|
-
|
17
|
+
|
18
18
|
# Execute the new block to add/merge new attributes
|
19
19
|
@stimulus_builder.instance_eval(&block)
|
20
20
|
end
|
@@ -24,10 +24,10 @@ module Vident
|
|
24
24
|
if @stimulus_builder.nil? && superclass.respond_to?(:stimulus_dsl_attributes)
|
25
25
|
return superclass.stimulus_dsl_attributes(component_instance)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
# Ensure inheritance is applied at access time
|
29
29
|
ensure_inheritance_merged
|
30
|
-
|
30
|
+
|
31
31
|
@stimulus_builder&.to_attributes(component_instance) || {}
|
32
32
|
end
|
33
33
|
|
@@ -35,7 +35,7 @@ module Vident
|
|
35
35
|
|
36
36
|
def ensure_inheritance_merged
|
37
37
|
return if @inheritance_merged || @stimulus_builder.nil?
|
38
|
-
|
38
|
+
|
39
39
|
if superclass.respond_to?(:stimulus_dsl_builder, true)
|
40
40
|
parent_builder = superclass.send(:stimulus_dsl_builder)
|
41
41
|
if parent_builder
|
@@ -71,4 +71,4 @@ module Vident
|
|
71
71
|
resolved
|
72
72
|
end
|
73
73
|
end
|
74
|
-
end
|
74
|
+
end
|
data/lib/vident/version.rb
CHANGED
data/lib/vident.rb
CHANGED
@@ -46,7 +46,7 @@ require "vident/stimulus_component"
|
|
46
46
|
require "vident/component_class_lists"
|
47
47
|
require "vident/component_attribute_resolver"
|
48
48
|
require "vident/stimulus_builder"
|
49
|
-
require "vident/
|
49
|
+
require "vident/stimulus_helper"
|
50
50
|
|
51
51
|
require "vident/component"
|
52
52
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vident
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.alpha3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Ierodiaconou
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-07-
|
10
|
+
date: 2025-07-21 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: railties
|
@@ -102,7 +102,7 @@ files:
|
|
102
102
|
- lib/vident/stimulus_controller.rb
|
103
103
|
- lib/vident/stimulus_controller_collection.rb
|
104
104
|
- lib/vident/stimulus_data_attribute_builder.rb
|
105
|
-
- lib/vident/
|
105
|
+
- lib/vident/stimulus_helper.rb
|
106
106
|
- lib/vident/stimulus_outlet.rb
|
107
107
|
- lib/vident/stimulus_outlet_collection.rb
|
108
108
|
- lib/vident/stimulus_target.rb
|