vident 0.7.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,7 @@ module Vident
15
15
  options = self.class.attribute_options
16
16
  default = options&.dig(attr_name, :default)
17
17
  allow_nil = options[attr_name] ? options[attr_name].fetch(:allow_nil, true) : true
18
+
18
19
  if attributes&.include? attr_name
19
20
  value = attributes[attr_name]
20
21
  @__attributes[attr_name] = (value.nil? && default) ? default : value
@@ -41,6 +42,8 @@ module Vident
41
42
  class_methods do
42
43
  def inherited(subclass)
43
44
  subclass.instance_variable_set(:@attribute_ivar_names, @attribute_ivar_names.clone)
45
+ subclass.instance_variable_set(:@attribute_names, @attribute_names.clone)
46
+ subclass.instance_variable_set(:@attribute_options, @attribute_options.clone)
44
47
  super
45
48
  end
46
49
 
data/lib/vident/base.rb CHANGED
@@ -33,15 +33,7 @@ module Vident
33
33
  end
34
34
 
35
35
  def identifier_name_path
36
- if phlex_component?
37
- name.remove("Views::").underscore
38
- else
39
- name.underscore
40
- end
41
- end
42
-
43
- def phlex_component?
44
- @phlex_component ||= ancestors.map(&:name).include?("Phlex::HTML")
36
+ name.underscore
45
37
  end
46
38
 
47
39
  private
@@ -52,7 +44,7 @@ module Vident
52
44
  def #{attr_name}
53
45
  #{@attribute_ivar_names[attr_name]}
54
46
  end
55
-
47
+
56
48
  def #{attr_name}?
57
49
  #{@attribute_ivar_names[attr_name]}.present?
58
50
  end
@@ -95,25 +87,6 @@ module Vident
95
87
 
96
88
  # HTML and attribute definition and creation
97
89
 
98
- # Helper to create the main element
99
- def parent_element(**options)
100
- @parent_element ||= begin
101
- # Note: we cant mix phlex and view_component render contexts
102
- klass = if self.class.phlex_component?
103
- RootComponent::UsingPhlexHTML
104
- else
105
- RootComponent::UsingViewComponent
106
- end
107
- element_attrs = options
108
- .except(:id, :element_tag, :html_options, :controller, :controllers, :actions, :targets, :named_classes, :data_maps)
109
- .merge(
110
- stimulus_options_for_component(options)
111
- )
112
- klass.new(**element_attrs)
113
- end
114
- end
115
- alias_method :root, :parent_element
116
-
117
90
  # FIXME: if we call them before `root` we will setup the root element before we intended
118
91
  # The separation between component and root element is a bit messy. Might need rethinking.
119
92
  delegate :action, :target, :named_classes, to: :root
@@ -155,6 +128,12 @@ module Vident
155
128
 
156
129
  private
157
130
 
131
+ def parent_element_attributes(options)
132
+ options
133
+ .except(:id, :element_tag, :html_options, :controller, :controllers, :actions, :targets, :named_classes, :data_maps)
134
+ .merge(stimulus_options_for_component(options))
135
+ end
136
+
158
137
  # Prepare the stimulus attributes for a StimulusComponent
159
138
  def stimulus_options_for_component(options)
160
139
  {
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vident
4
+ # Rails fragment caching works by either expecting the cached key object to respond to `cache_key` or for that object
5
+ # to be an array or hash.
6
+ module Caching
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def inherited(subclass)
11
+ subclass.instance_variable_set(:@named_cache_key_attributes, @named_cache_key_attributes.clone)
12
+ super
13
+ end
14
+
15
+ def with_cache_key(*attrs, name: :_collection)
16
+ # Add view file to cache key
17
+ attrs << :component_modified_time
18
+ attrs << :attributes
19
+ named_cache_key_includes(name, *attrs.uniq)
20
+ end
21
+
22
+ attr_reader :named_cache_key_attributes
23
+
24
+ # Components can be used with fragment caching, but you need to be careful! Read on...
25
+ #
26
+ # <% cache component do %>
27
+ # <%= render component %>
28
+ # <% end %>
29
+ #
30
+ # The most important point is that Rails cannot track dependencies on the component itself, so you need to
31
+ # be careful to be explicit on the attributes, and manually specify any sub Viewcomponent dependencies that the
32
+ # component has. The assumption is that the subcomponent takes any attributes from the parent, so the cache key
33
+ # depends on the parent component attributes. Otherwise changes to the parent or sub component views/Ruby class
34
+ # will result in different cache keys too. Of course if you invalidate all cache keys with a modifier on deploy
35
+ # then no need to worry about changing the cache key on component changes, only on attribute/data changes.
36
+ #
37
+ # A big caveat is that the cache key cannot depend on anything related to the view_context of the component (such
38
+ # as `helpers` as the key is created before the rending pipline is invoked (which is when the view_context is set).
39
+ def depends_on(*klasses)
40
+ @component_dependencies ||= []
41
+ @component_dependencies += klasses
42
+ end
43
+
44
+ attr_reader :component_dependencies
45
+
46
+ def component_modified_time
47
+ return @component_modified_time if Rails.env.production? && @component_modified_time
48
+
49
+ raise StandardError, "Must implement current_component_modified_time" unless respond_to?(:current_component_modified_time)
50
+
51
+ # FIXME: This could stack overflow if there are circular dependencies
52
+ deps = component_dependencies&.map(&:component_modified_time)&.join("-") || ""
53
+ @component_modified_time = deps + current_component_modified_time
54
+ end
55
+
56
+ private
57
+
58
+ def named_cache_key_includes(name, *attrs)
59
+ define_cache_key_method unless @named_cache_key_attributes
60
+ @named_cache_key_attributes ||= {}
61
+ @named_cache_key_attributes[name] = attrs
62
+ end
63
+
64
+ def define_cache_key_method
65
+ # If the presenter defines cache key setup then define the method. Otherwise Rails assumes this
66
+ # will return a valid key if the class will respond to this
67
+ define_method :cache_key do |n = :_collection|
68
+ if defined?(@cache_key)
69
+ return @cache_key[n] if @cache_key.key?(n)
70
+ else
71
+ @cache_key ||= {}
72
+ end
73
+ generate_cache_key(n)
74
+ @cache_key[n]
75
+ end
76
+ end
77
+ end
78
+
79
+ # Component modified time which is combined with other cache key attributes to generate cache key for an instance
80
+ def component_modified_time
81
+ self.class.component_modified_time
82
+ end
83
+
84
+ def cacheable?
85
+ respond_to? :cache_key
86
+ end
87
+
88
+ def cache_key_modifier
89
+ ENV["RAILS_CACHE_ID"]
90
+ end
91
+
92
+ def cache_keys_for_sources(key_attributes)
93
+ sources = key_attributes.flat_map { |n| n.is_a?(Proc) ? instance_eval(&n) : send(n) }
94
+ sources.compact.map do |item|
95
+ next if item == self
96
+ generate_item_cache_key_from(item)
97
+ end
98
+ end
99
+
100
+ def generate_item_cache_key_from(item)
101
+ if item.respond_to? :cache_key_with_version
102
+ item.cache_key_with_version
103
+ elsif item.respond_to? :cache_key
104
+ item.cache_key
105
+ elsif item.is_a?(String)
106
+ Digest::SHA1.hexdigest(item)
107
+ else
108
+ Digest::SHA1.hexdigest(Marshal.dump(item))
109
+ end
110
+ end
111
+
112
+ def generate_cache_key(index)
113
+ key_attributes = self.class.named_cache_key_attributes[index]
114
+ return nil unless key_attributes
115
+ key = "#{self.class.name}/#{cache_keys_for_sources(key_attributes).join("/")}"
116
+ raise StandardError, "Cache key for key #{key} is blank!" if key.blank?
117
+ @cache_key[index] = cache_key_modifier.present? ? "#{key}/#{cache_key_modifier}" : key
118
+ end
119
+ end
120
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./attributes/not_typed"
4
-
5
3
  module Vident
6
4
  module Component
7
5
  extend ActiveSupport::Concern
@@ -0,0 +1,15 @@
1
+ module Vident
2
+ class Engine < ::Rails::Engine
3
+ lib_path = File.expand_path("../../../lib/", __FILE__)
4
+ config.autoload_paths << lib_path
5
+ config.eager_load_paths << lib_path
6
+
7
+ config.before_initialize do
8
+ Rails.autoloaders.each do |autoloader|
9
+ autoloader.inflector.inflect(
10
+ "version" => "VERSION"
11
+ )
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vident
4
+ module RootComponent
5
+ def initialize(
6
+ controllers: nil,
7
+ actions: nil,
8
+ targets: nil,
9
+ named_classes: nil, # https://stimulus.hotwired.dev/reference/css-classes
10
+ data_maps: nil,
11
+ element_tag: nil,
12
+ id: nil,
13
+ html_options: nil
14
+ )
15
+ @element_tag = element_tag
16
+ @html_options = html_options
17
+ @id = id
18
+ @controllers = Array.wrap(controllers)
19
+ @actions = actions
20
+ @targets = targets
21
+ @named_classes = named_classes
22
+ @data_map_kvs = {}
23
+ @data_maps = data_maps
24
+ end
25
+
26
+ # The view component's helpers for setting stimulus data-* attributes on this component.
27
+
28
+ # TODO: rename
29
+ # Create a Stimulus action string, and returns it
30
+ # examples:
31
+ # action(:my_thing) => "current_controller#myThing"
32
+ # action(:click, :my_thing) => "click->current_controller#myThing"
33
+ # action("click->current_controller#myThing") => "click->current_controller#myThing"
34
+ # action("path/to/current", :my_thing) => "path--to--current_controller#myThing"
35
+ # action(:click, "path/to/current", :my_thing) => "click->path--to--current_controller#myThing"
36
+ def action(*args)
37
+ part1, part2, part3 = args
38
+ (args.size == 1) ? parse_action_arg(part1) : parse_multiple_action_args(part1, part2, part3)
39
+ end
40
+
41
+ def action_data_attribute(*actions)
42
+ {action: parse_actions(actions).join(" ")}
43
+ end
44
+
45
+ # TODO: rename & make stimulus Target class instance and returns it, which can convert to String
46
+ # Create a Stimulus Target and returns it
47
+ # examples:
48
+ # target(:my_target) => {controller: 'current_controller' name: 'myTarget'}
49
+ # target("path/to/current", :my_target) => {controller: 'path--to--current_controller', name: 'myTarget'}
50
+ def target(name, part2 = nil)
51
+ if part2.nil?
52
+ {controller: implied_controller_name, name: js_name(name)}
53
+ else
54
+ {controller: stimulize_path(name), name: js_name(part2)}
55
+ end
56
+ end
57
+
58
+ def target_data_attribute(name)
59
+ build_target_data_attributes([target(name)])
60
+ end
61
+
62
+ # Getter for a named classes list so can be used in view to set initial state on SSR
63
+ # Returns a String of classes that can be used in a `class` attribute.
64
+ def named_classes(*names)
65
+ names.map { |name| convert_classes_list_to_string(@named_classes[name]) }.join(" ")
66
+ end
67
+
68
+ # Helpers for generating the Stimulus data-* attributes directly
69
+
70
+ # Return the HTML `data-controller` attribute for the given controllers
71
+ def with_controllers(*controllers_to_set)
72
+ "data-controller=\"#{controller_list(controllers_to_set)}\"".html_safe
73
+ end
74
+
75
+ # Return the HTML `data-target` attribute for the given targets
76
+ def as_targets(*targets)
77
+ attrs = build_target_data_attributes(parse_targets(targets))
78
+ attrs.map { |dt, n| "data-#{dt}=\"#{n}\"" }.join(" ").html_safe
79
+ end
80
+ alias_method :as_target, :as_targets
81
+
82
+ # Return the HTML `data-action` attribute for the given actions
83
+ def with_actions(*actions_to_set)
84
+ "data-action='#{parse_actions(actions_to_set).join(" ")}'".html_safe
85
+ end
86
+ alias_method :with_action, :with_actions
87
+
88
+ private
89
+
90
+ # An implicit Stimulus controller name is built from the implicit controller path
91
+ def implied_controller_name
92
+ stimulize_path(implied_controller_path)
93
+ end
94
+
95
+ # When using the DSL if you dont specify, the first controller is implied
96
+ def implied_controller_path
97
+ @controllers&.first || raise(StandardError, "No controllers have been specified")
98
+ end
99
+
100
+ # A complete list of Stimulus controllers for this component
101
+ def controller_list(controllers_to_set)
102
+ controllers_to_set&.map { |c| stimulize_path(c) }&.join(" ")
103
+ end
104
+
105
+ # Complete list of actions ready to be use in the data-action attribute
106
+ def action_list(actions_to_parse)
107
+ return nil unless actions_to_parse&.size&.positive?
108
+ parse_actions(actions_to_parse).join(" ")
109
+ end
110
+
111
+ # Complete list of targets ready to be use in the data attributes
112
+ def target_list
113
+ return {} unless @targets&.size&.positive?
114
+ build_target_data_attributes(parse_targets(@targets))
115
+ end
116
+
117
+ def named_classes_list
118
+ return {} unless @named_classes&.size&.positive?
119
+ build_named_classes_data_attributes(@named_classes)
120
+ end
121
+
122
+ # stimulus "data-*" attributes map for this component
123
+ def tag_data_attributes
124
+ {controller: controller_list(@controllers), action: action_list(@actions)}
125
+ .merge!(target_list)
126
+ .merge!(named_classes_list)
127
+ .merge!(data_map_attributes)
128
+ .compact_blank!
129
+ end
130
+
131
+ # Actions can be specified as a symbol, in which case they imply an action on the primary
132
+ # controller, or as a string in which case it implies an action that is already fully qualified
133
+ # stimulus action.
134
+ # 1 Symbol: :my_action => "my_controller#myAction"
135
+ # 1 String: "my_controller#myAction"
136
+ # 2 Symbols: [:click, :my_action] => "click->my_controller#myAction"
137
+ # 1 String, 1 Symbol: ["path/to/controller", :my_action] => "path--to--controller#myAction"
138
+ # 1 Symbol, 1 String, 1 Symbol: [:hover, "path/to/controller", :my_action] => "hover->path--to--controller#myAction"
139
+
140
+ def parse_action_arg(part1)
141
+ if part1.is_a?(Symbol)
142
+ # 1 symbol arg, name of method on this controller
143
+ "#{implied_controller_name}##{js_name(part1)}"
144
+ elsif part1.is_a?(String)
145
+ # 1 string arg, fully qualified action
146
+ part1
147
+ end
148
+ end
149
+
150
+ def parse_multiple_action_args(part1, part2, part3)
151
+ if part3.nil? && part1.is_a?(Symbol)
152
+ # 2 symbol args = event + action
153
+ "#{part1}->#{implied_controller_name}##{js_name(part2)}"
154
+ elsif part3.nil?
155
+ # 1 string arg, 1 symbol = controller + action
156
+ "#{stimulize_path(part1)}##{js_name(part2)}"
157
+ else
158
+ # 1 symbol, 1 string, 1 symbol = as above but with event
159
+ "#{part1}->#{stimulize_path(part2)}##{js_name(part3)}"
160
+ end
161
+ end
162
+
163
+ # Parse actions, targets and attributes that are passed in as symbols or strings
164
+
165
+ def parse_targets(targets)
166
+ targets.map { |n| parse_target(n) }
167
+ end
168
+
169
+ def parse_target(raw_target)
170
+ return raw_target if raw_target.is_a?(String)
171
+ return raw_target if raw_target.is_a?(Hash)
172
+ target(raw_target)
173
+ end
174
+
175
+ def build_target_data_attributes(targets)
176
+ targets.map { |t| ["#{t[:controller]}-target".to_sym, t[:name]] }.to_h
177
+ end
178
+
179
+ def parse_actions(actions)
180
+ actions.map! { |a| a.is_a?(String) ? a : action(*a) }
181
+ end
182
+
183
+ def parse_attributes(attrs, controller = nil)
184
+ attrs.transform_keys { |k| "#{controller || implied_controller_name}-#{k}" }
185
+ end
186
+
187
+ def data_map_attributes
188
+ return {} unless @data_maps
189
+ @data_maps.each_with_object({}) do |m, obj|
190
+ if m.is_a?(Hash)
191
+ obj.merge!(parse_attributes(m))
192
+ elsif m.is_a?(Array)
193
+ controller_path = m.first
194
+ data = m.last
195
+ obj.merge!(parse_attributes(data, stimulize_path(controller_path)))
196
+ end
197
+ end
198
+ end
199
+
200
+ def parse_named_classes_hash(named_classes)
201
+ named_classes.map do |name, classes|
202
+ logical_name = name.to_s.dasherize
203
+ classes_str = convert_classes_list_to_string(classes)
204
+ if classes.is_a?(Hash)
205
+ {controller: stimulize_path(classes[:controller_path]), name: logical_name, classes: classes_str}
206
+ else
207
+ {controller: implied_controller_name, name: logical_name, classes: classes_str}
208
+ end
209
+ end
210
+ end
211
+
212
+ def build_named_classes_data_attributes(named_classes)
213
+ parse_named_classes_hash(named_classes)
214
+ .map { |c| ["#{c[:controller]}-#{c[:name]}-class", c[:classes]] }
215
+ .to_h
216
+ end
217
+
218
+ def convert_classes_list_to_string(classes)
219
+ return "" if classes.nil?
220
+ return classes if classes.is_a?(String)
221
+ return classes.join(" ") if classes.is_a?(Array)
222
+ classes[:classes].is_a?(Array) ? classes[:classes].join(" ") : classes[:classes]
223
+ end
224
+
225
+ # Convert a file path to a stimulus controller name
226
+ def stimulize_path(path)
227
+ path.split("/").map { |p| p.to_s.dasherize }.join("--")
228
+ end
229
+
230
+ # Convert a Ruby 'snake case' string to a JavaScript camel case strings
231
+ def js_name(name)
232
+ name.to_s.camelize(:lower)
233
+ end
234
+ end
235
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vident
4
- VERSION = "0.7.0"
4
+ VERSION = "0.9.0"
5
5
  end
data/lib/vident.rb CHANGED
@@ -1,41 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "vident/version"
4
- require_relative "vident/railtie"
3
+ require "vident/version"
4
+ require "vident/engine"
5
5
 
6
6
  module Vident
7
- class << self
8
- def configuration
9
- @configuration ||= Configuration.new
10
- end
11
-
12
- def configure
13
- yield(configuration) if block_given?
14
- configuration
15
- end
16
- end
17
-
18
- class Configuration
19
- attr_accessor :include_i18n_helpers
20
-
21
- def initialize
22
- @include_i18n_helpers = true
23
- end
24
- end
7
+ # Your code goes here...
25
8
  end
26
-
27
- require_relative "vident/stable_id"
28
- require_relative "vident/root_component/base"
29
- require_relative "vident/root_component/using_better_html"
30
- require_relative "vident/root_component/using_phlex_html"
31
- require_relative "vident/root_component/using_view_component"
32
- require_relative "vident/base"
33
- require_relative "vident/component"
34
- require_relative "vident/typed_component"
35
- require_relative "vident/caching/cache_key"
36
- require_relative "vident/tailwind" if Gem.loaded_specs.has_key? "tailwind_merge"
37
- require_relative "vident/testing/attributes_tester"
38
- require_relative "vident/testing/auto_test"
39
-
40
- # TODO: what if not using view_component?
41
- require_relative "vident/test_case"
metadata CHANGED
@@ -1,22 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vident
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Ierodiaconou
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-08 00:00:00.000000000 Z
11
+ date: 2023-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
14
+ name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '6.0'
19
+ version: '7'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '8'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '6.0'
29
+ version: '7'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '8'
@@ -40,43 +40,25 @@ executables: []
40
40
  extensions: []
41
41
  extra_rdoc_files: []
42
42
  files:
43
- - ".standard.yml"
44
- - CHANGELOG.md
45
- - CODE_OF_CONDUCT.md
46
- - Gemfile
47
- - LICENSE.txt
48
43
  - README.md
49
44
  - Rakefile
50
- - examples/avatar.png
51
- - examples/ex1.gif
52
- - lib/tasks/vident.rake
45
+ - lib/tasks/vident_tasks.rake
53
46
  - lib/vident.rb
54
47
  - lib/vident/attributes/not_typed.rb
55
- - lib/vident/attributes/typed.rb
56
- - lib/vident/attributes/typed_niling_struct.rb
57
- - lib/vident/attributes/types.rb
58
48
  - lib/vident/base.rb
59
- - lib/vident/caching/cache_key.rb
49
+ - lib/vident/caching.rb
60
50
  - lib/vident/component.rb
61
- - lib/vident/railtie.rb
62
- - lib/vident/root_component/base.rb
63
- - lib/vident/root_component/using_better_html.rb
64
- - lib/vident/root_component/using_phlex_html.rb
65
- - lib/vident/root_component/using_view_component.rb
51
+ - lib/vident/engine.rb
52
+ - lib/vident/root_component.rb
66
53
  - lib/vident/stable_id.rb
67
- - lib/vident/tailwind.rb
68
- - lib/vident/test_case.rb
69
- - lib/vident/testing/attributes_tester.rb
70
- - lib/vident/testing/auto_test.rb
71
- - lib/vident/typed_component.rb
72
54
  - lib/vident/version.rb
73
- - sig/vident.rbs
74
55
  homepage: https://github.com/stevegeek/vident
75
56
  licenses:
76
57
  - MIT
77
58
  metadata:
78
59
  homepage_uri: https://github.com/stevegeek/vident
79
60
  source_code_uri: https://github.com/stevegeek/vident
61
+ changelog_uri: https://github.com/stevegeek/vident/blob/main/CHANGELOG.md
80
62
  post_install_message:
81
63
  rdoc_options: []
82
64
  require_paths:
@@ -92,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
74
  - !ruby/object:Gem::Version
93
75
  version: '0'
94
76
  requirements: []
95
- rubygems_version: 3.3.26
77
+ rubygems_version: 3.4.10
96
78
  signing_key:
97
79
  specification_version: 4
98
80
  summary: Vident is the base of your design system implementation, which provides helpers
data/.standard.yml DELETED
@@ -1,3 +0,0 @@
1
- # For available configuration options, see:
2
- # https://github.com/testdouble/standard
3
- ruby_version: 3.0
data/CHANGELOG.md DELETED
@@ -1,79 +0,0 @@
1
-
2
- # Change Log
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
- and this project adheres to [Semantic Versioning](http://semver.org/).
7
-
8
- ## [Unreleased]
9
-
10
- ### Added
11
-
12
- ### Changed
13
-
14
- ### Fixed
15
-
16
- ## [0.7.0] - 2023-03-08
17
-
18
- ### Added
19
-
20
- - new `Vident::Tailwind` module which uses [tailwind_merge](https://github.com/gjtorikian/tailwind_merge) to merge TailwindCSS classes
21
-
22
- ### Changed
23
-
24
- - Removed a dependency on intenal constants from `phlex`
25
-
26
- ## [0.6.3] - 2023-03-03
27
-
28
- ### Fixed
29
-
30
- - Fix for changes to HTML tag collection in Phlex
31
-
32
-
33
- ## [0.6.2] - 2023-02-23
34
-
35
- ### Fixed
36
-
37
- - Element tag options are not set when no ID is provided
38
-
39
-
40
- ## [0.6.1] - 2023-02-20
41
-
42
- ### Fixed
43
-
44
- - `better_html` support fix for aliased dsl methods
45
-
46
-
47
- ## [0.6.0] - 2023-02-20
48
-
49
- ### Added
50
-
51
- - Experimental support for `better_html` in the root components (the stimulus attributes are generated with `html_attributes`)
52
-
53
-
54
-
55
- ## [0.5.1] - 2023-02-17
56
-
57
- ### Added
58
-
59
- - N/A
60
-
61
- ### Changed
62
-
63
- - N/A
64
-
65
- ### Fixed
66
-
67
- - Typed attributes was not always using custom coercion methods if they were defined
68
-
69
- ### Removed
70
-
71
- - N/A
72
-
73
- ### Deprecated
74
-
75
- - N/A
76
-
77
- ### Security
78
-
79
- - N/A