vident 1.0.0.alpha2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7144408178f3fedee324dc23604af7baca5db589520d3cb4ea1413a88e4c93c0
4
- data.tar.gz: 742e8db9df1d0f72e701ccec290693be799408b70263fd5a7c75a1c1987a0acb
3
+ metadata.gz: 1ae2c093011a8047255f21fff2b284520d9be75660af61afc511c85bfdcc9f76
4
+ data.tar.gz: 47bbde103e62632fca8a11bb1ddd6321dd8c6c8711d21790a51a3e657e3d6f66
5
5
  SHA512:
6
- metadata.gz: c1ccac1a695a9a915e87675973c7a09143582cb7775d6fd9a89d24c426a35cad5aa2d0e7adc424d680ae02d4cb767645a11394c05981cff2724c01482ccf44f2
7
- data.tar.gz: 315951c114e8ecb5db720d45dc8236aabb34b7442eec520e47d8eb4b9472728b50c0b6a430e9ead6e85c292640eb6cafe03f034bf7ca6606e422e3c0c837c544
6
+ metadata.gz: df35e4be8597d580ad4f50b63f99c1e0a8032fd52c9c06676b6d4db9ee15a781f80d00c5112c87047238361560b5a131e60f11800e07c03f904d1e781fed3312
7
+ data.tar.gz: 5794832b1bb4a4abbc532beabdbe9133c3a45b7ef42eca8d11660051466a7b64298af3bcb8c7c90c55381a25bfec0680afe389f319c2b8ffc1602f1fb3f47d16
data/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ 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.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.
8
16
 
9
17
  ## [1.0.0.alpha2] - 2025-07-08
10
18
 
data/README.md CHANGED
@@ -76,21 +76,23 @@ class ButtonComponent < Vident::ViewComponent::Base
76
76
 
77
77
  # Configure Stimulus integration
78
78
  stimulus do
79
- actions [:click, :handle_click]
80
- # Static values
81
- values loading_duration: 1000
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
- values api_url: -> { Rails.application.routes.url_helpers.api_items_path }
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
- classes size: -> { @items.count > 10 ? "large" : "small" }
89
+ classes loading: "opacity-50 cursor-wait",
90
+ size: -> { @items.count > 10 ? "large" : "small" }
90
91
  end
91
92
 
92
93
  def call
93
94
  root_element do |component|
95
+ # Wire up targets etc
94
96
  component.tag(:span, stimulus_target: :status) do
95
97
  @text
96
98
  end
@@ -99,6 +101,7 @@ class ButtonComponent < Vident::ViewComponent::Base
99
101
 
100
102
  private
101
103
 
104
+ # Configure your components root HTML element
102
105
  def root_element_attributes
103
106
  {
104
107
  element_tag: @url ? :a : :button,
@@ -106,7 +109,8 @@ class ButtonComponent < Vident::ViewComponent::Base
106
109
  }
107
110
  end
108
111
 
109
- def element_classes
112
+ # optionally add logic to determine initial classes
113
+ def root_element_classes
110
114
  base_classes = "btn"
111
115
  case @style
112
116
  when :primary
@@ -263,7 +267,7 @@ The `root_element` helper method renders your component's root element with all
263
267
 
264
268
  ```ruby
265
269
  # In your component class
266
- def element_classes
270
+ def root_element_classes
267
271
  ["card", featured? ? "card-featured" : nil]
268
272
  end
269
273
 
@@ -619,7 +623,7 @@ class StyledComponent < Vident::ViewComponent::Base
619
623
  private
620
624
 
621
625
  # Classes on the root element
622
- def element_classes
626
+ def root_element_classes
623
627
  ["base-class", variant_class]
624
628
  end
625
629
 
@@ -653,7 +657,7 @@ class TailwindComponent < Vident::ViewComponent::Base
653
657
 
654
658
  private
655
659
 
656
- def element_classes
660
+ def root_element_classes
657
661
  # Conflicts with size_class will be resolved automatically
658
662
  "p-2 text-sm #{size_class}"
659
663
  end
@@ -6,12 +6,23 @@ module Vident
6
6
  class ClassListBuilder
7
7
  CLASSNAME_SEPARATOR = " "
8
8
 
9
- def initialize(tailwind_merger: nil, component_name: nil, element_classes: nil, html_class: nil, additional_classes: nil)
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(element_classes)) if element_classes
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)
@@ -16,6 +16,13 @@ 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
@@ -29,7 +36,7 @@ module Vident
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 element_classes
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,7 +4,7 @@ module Vident
4
4
  module ComponentAttributeResolver
5
5
  private
6
6
 
7
- # FIXME: in a view_component the parsing of html_options might have to be in `before_render`
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
 
@@ -14,8 +14,8 @@ module Vident
14
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
- @html_options[:class] = render_classes(extra[:classes])
18
- @html_options[:id] = (extra[:id] || id) unless @html_options.key?(:id)
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)
@@ -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(extra_classes = nil) = class_list_builder.build(extra_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
- element_classes:,
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
  )
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vident
4
- VERSION = "1.0.0.alpha2"
4
+ VERSION = "1.0.0.alpha3"
5
5
 
6
6
  # Shared version for all vident gems
7
7
  def self.version
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.alpha2
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-08 00:00:00.000000000 Z
10
+ date: 2025-07-21 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: railties