vident 1.0.0.alpha1 → 1.0.0.alpha2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d59f73664008e87455784726ec60622da719f758449339ac3904f99c7b04b1b6
4
- data.tar.gz: d10178e8d4cfe43d441d8dde5b7540d847ecad01fea060024362d0e6c74735e6
3
+ metadata.gz: 7144408178f3fedee324dc23604af7baca5db589520d3cb4ea1413a88e4c93c0
4
+ data.tar.gz: 742e8db9df1d0f72e701ccec290693be799408b70263fd5a7c75a1c1987a0acb
5
5
  SHA512:
6
- metadata.gz: 4a605e928c5749975f0f4127c49192f6676ee349e979b3d9531013a2cd988228516a7b6a592155ea175e60e30648417c7c76bb3ec4535a1b26008baa27eb3eaf
7
- data.tar.gz: 1057b3d13ef990e098d0011f5b00ff0e020c605fae330c88baf0677f85fffa46ec1ff604e97276d6934e23ff1aaad03ddbd87856c1ca7bdcd555663d81b3cb06
6
+ metadata.gz: c1ccac1a695a9a915e87675973c7a09143582cb7775d6fd9a89d24c426a35cad5aa2d0e7adc424d680ae02d4cb767645a11394c05981cff2724c01482ccf44f2
7
+ data.tar.gz: 315951c114e8ecb5db720d45dc8236aabb34b7442eec520e47d8eb4b9472728b50c0b6a430e9ead6e85c292640eb6cafe03f034bf7ca6606e422e3c0c837c544
data/CHANGELOG.md CHANGED
@@ -5,7 +5,17 @@ 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.alpha1] - 2025-07-04
8
+
9
+ ## [1.0.0.alpha2] - 2025-07-08
10
+
11
+ ### Breaking
12
+ - `nil` values in Stimulus values are ok, but `nil` for an action/target/outlet makes no sense so is ignored.
13
+
14
+ ### Fixed
15
+
16
+ - `stimulus_scoped_event` must return a Symbol to work with `stimulus_action` and `stimulus_target` methods etc.
17
+
18
+ ## [1.0.0.alpha1] - 2025-07-08
9
19
 
10
20
  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
21
 
data/README.md CHANGED
@@ -90,8 +90,10 @@ class ButtonComponent < Vident::ViewComponent::Base
90
90
  end
91
91
 
92
92
  def call
93
- root_element do
94
- @text
93
+ root_element do |component|
94
+ component.tag(:span, stimulus_target: :status) do
95
+ @text
96
+ end
95
97
  end
96
98
  end
97
99
 
@@ -130,14 +132,19 @@ export default class extends Controller {
130
132
  loadingDuration: Number
131
133
  }
132
134
  static classes = ["loading"]
135
+ static targets = ["status"]
133
136
 
134
137
  handleClick(event) {
135
138
  // Increment counter
136
139
  this.clickedCountValue++
137
140
 
141
+ // Store original text
142
+ const originalText = this.statusTarget.textContent
143
+
138
144
  // Add loading state
139
145
  this.element.classList.add(this.loadingClass)
140
146
  this.element.disabled = true
147
+ this.statusTarget.textContent = "Loading..."
141
148
 
142
149
  // Use the loading duration from the component
143
150
  setTimeout(() => {
@@ -145,7 +152,7 @@ export default class extends Controller {
145
152
  this.element.disabled = false
146
153
 
147
154
  // Update text to show count
148
- this.element.textContent = `${this.element.textContent} (${this.clickedCountValue})`
155
+ this.statusTarget.textContent = `${originalText} (${this.clickedCountValue})`
149
156
  }, this.loadingDurationValue)
150
157
  }
151
158
  }
@@ -178,7 +185,7 @@ The rendered HTML includes all Stimulus data attributes:
178
185
  data-button-component-loading-duration-value="1000"
179
186
  data-button-component-loading-class="opacity-50 cursor-wait"
180
187
  id="button-component-123">
181
- Save
188
+ <span data-button-component-target="status">Save</span>
182
189
  </button>
183
190
 
184
191
  <!-- Second button with pre-set count -->
@@ -189,7 +196,7 @@ The rendered HTML includes all Stimulus data attributes:
189
196
  data-button-component-loading-duration-value="1000"
190
197
  data-button-component-loading-class="opacity-50 cursor-wait"
191
198
  id="button-component-456">
192
- Submit
199
+ <span data-button-component-target="status">Submit</span>
193
200
  </button>
194
201
  ```
195
202
 
@@ -218,6 +225,29 @@ class CardComponent < Vident::ViewComponent::Base
218
225
  end
219
226
  ```
220
227
 
228
+ ### Post-Initialization Hooks
229
+
230
+ Vident provides a hook for performing actions after component initialization:
231
+
232
+ ```ruby
233
+ class MyComponent < Vident::ViewComponent::Base
234
+ prop :data, Hash, default: -> { {} }
235
+
236
+ def after_component_initialize
237
+ @processed_data = process_data(@data)
238
+ end
239
+
240
+ private
241
+
242
+ def process_data(data)
243
+ # Your initialization logic here
244
+ data.transform_values(&:upcase)
245
+ end
246
+ end
247
+ ```
248
+
249
+ **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`.
250
+
221
251
  ### Built-in Properties
222
252
 
223
253
  Every Vident component includes these properties:
@@ -389,7 +419,7 @@ Vident provides helper methods to generate scoped event names for dispatching cu
389
419
  class MyComponent < Vident::ViewComponent::Base
390
420
  stimulus do
391
421
  # Define an action that responds to a scoped event
392
- actions [stimulus_scoped_event_on_window(:data_loaded), :handle_data_loaded]
422
+ actions -> { [stimulus_scoped_event_on_window(:data_loaded), :handle_data_loaded] }
393
423
  end
394
424
 
395
425
  def handle_click
@@ -22,7 +22,7 @@ module Vident
22
22
 
23
23
  include TagHelper
24
24
  include Tailwind
25
- include StimulusDSL
25
+ include StimulusHelper
26
26
 
27
27
  # Override this method to perform any initialisation after attributes are set
28
28
  def after_component_initialize
@@ -11,7 +11,7 @@ module Vident
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
17
  @html_options[:class] = render_classes(extra[:classes])
@@ -36,20 +36,19 @@ module Vident
36
36
  add_stimulus_actions(dsl_attrs[:stimulus_actions]) if dsl_attrs[:stimulus_actions]
37
37
  add_stimulus_targets(dsl_attrs[:stimulus_targets]) if dsl_attrs[:stimulus_targets]
38
38
  add_stimulus_outlets(dsl_attrs[:stimulus_outlets]) if dsl_attrs[:stimulus_outlets]
39
-
39
+
40
40
  # Add static values (now includes resolved proc values)
41
41
  add_stimulus_values(dsl_attrs[:stimulus_values]) if dsl_attrs[:stimulus_values]
42
-
42
+
43
43
  # Resolve and add values from props
44
44
  if dsl_attrs[:stimulus_values_from_props]
45
45
  resolved_values = resolve_values_from_props(dsl_attrs[:stimulus_values_from_props])
46
46
  add_stimulus_values(resolved_values) unless resolved_values.empty?
47
47
  end
48
-
48
+
49
49
  add_stimulus_classes(dsl_attrs[:stimulus_classes]) if dsl_attrs[:stimulus_classes]
50
50
  end
51
51
 
52
-
53
52
  # Prepare stimulus collections and implied controller path from the given attributes, called after initialization
54
53
  def prepare_stimulus_collections # Convert raw attributes to stimulus attribute collections
55
54
  @stimulus_controllers_collection = stimulus_controllers(*Array.wrap(@stimulus_controllers))
@@ -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] = resolve_values(@actions, component_instance) unless @actions.empty?
57
- attrs[:stimulus_targets] = resolve_values(@targets, component_instance) unless @targets.empty?
58
- attrs[:stimulus_values] = resolve_hash_values(@values, component_instance) unless @values.empty?
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] = resolve_hash_values(@classes, component_instance) unless @classes.empty?
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
- def resolve_values(array, component_instance)
99
- array.map do |value|
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
- value
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
- def resolve_hash_values(hash, component_instance)
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 StimulusDSL
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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vident
4
- VERSION = "1.0.0.alpha1"
4
+ VERSION = "1.0.0.alpha2"
5
5
 
6
6
  # Shared version for all vident gems
7
7
  def self.version
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/stimulus_dsl"
49
+ require "vident/stimulus_helper"
50
50
 
51
51
  require "vident/component"
52
52
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vident
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha1
4
+ version: 1.0.0.alpha2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Ierodiaconou
@@ -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/stimulus_dsl.rb
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