tailmix 0.1.0 → 0.4.5

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/README.md +147 -85
  4. data/app/javascript/tailmix/finder.js +12 -0
  5. data/app/javascript/tailmix/index.js +7 -0
  6. data/app/javascript/tailmix/mutator.js +28 -0
  7. data/app/javascript/tailmix/runner.js +7 -0
  8. data/app/javascript/tailmix/stimulus_adapter.js +37 -0
  9. data/examples/_modal_component.arb +36 -0
  10. data/examples/modal_component.rb +180 -0
  11. data/lib/generators/tailmix/install_generator.rb +19 -0
  12. data/lib/tailmix/definition/context_builder.rb +39 -0
  13. data/lib/tailmix/definition/contexts/action_builder.rb +31 -0
  14. data/lib/tailmix/definition/contexts/actions/element_builder.rb +30 -0
  15. data/lib/tailmix/definition/contexts/attribute_builder.rb +21 -0
  16. data/lib/tailmix/definition/contexts/dimension_builder.rb +16 -0
  17. data/lib/tailmix/definition/contexts/element_builder.rb +41 -0
  18. data/lib/tailmix/definition/contexts/stimulus_builder.rb +101 -0
  19. data/lib/tailmix/definition/merger.rb +93 -0
  20. data/lib/tailmix/definition/result.rb +31 -0
  21. data/lib/tailmix/definition.rb +11 -0
  22. data/lib/tailmix/dev/docs.rb +82 -0
  23. data/lib/tailmix/dev/stimulus_generator.rb +124 -0
  24. data/lib/tailmix/dev/tools.rb +26 -0
  25. data/lib/tailmix/engine.rb +17 -0
  26. data/lib/tailmix/html/attributes.rb +71 -0
  27. data/lib/tailmix/html/class_list.rb +79 -0
  28. data/lib/tailmix/html/data_map.rb +95 -0
  29. data/lib/tailmix/html/stimulus_builder.rb +65 -0
  30. data/lib/tailmix/runtime/action.rb +51 -0
  31. data/lib/tailmix/runtime/context.rb +66 -0
  32. data/lib/tailmix/runtime/facade_builder.rb +23 -0
  33. data/lib/tailmix/runtime/stimulus/compiler.rb +59 -0
  34. data/lib/tailmix/runtime.rb +14 -0
  35. data/lib/tailmix/version.rb +1 -1
  36. data/lib/tailmix.rb +48 -18
  37. metadata +33 -10
  38. data/examples/status_badge_component.rb +0 -44
  39. data/lib/tailmix/dimension.rb +0 -18
  40. data/lib/tailmix/element.rb +0 -24
  41. data/lib/tailmix/manager.rb +0 -58
  42. data/lib/tailmix/part.rb +0 -39
  43. data/lib/tailmix/resolver.rb +0 -28
  44. data/lib/tailmix/schema.rb +0 -18
  45. data/lib/tailmix/utils.rb +0 -15
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require_relative "class_list"
5
+ require_relative "data_map"
6
+
7
+ module Tailmix
8
+ module HTML
9
+ class Attributes < Hash
10
+ attr_reader :element_name
11
+
12
+ def initialize(initial_hash = {}, element_name: nil)
13
+ @element_name = element_name
14
+ super()
15
+ self[:class] = ClassList.new
16
+ self[:data] = DataMap.new
17
+ merge!(initial_hash)
18
+ end
19
+
20
+ def each(&block)
21
+ to_h.each(&block)
22
+ end
23
+
24
+ def to_h
25
+ final_attrs = select { |k, _| !%i[class data].include?(k.to_sym) }
26
+ class_string = self[:class].to_s
27
+ final_attrs[:class] = class_string unless class_string.empty?
28
+ final_attrs.merge!(self[:data].to_h)
29
+
30
+ selector_attr = Tailmix.configuration.element_selector_attribute
31
+ if selector_attr && @element_name
32
+ final_attrs[selector_attr] = @element_name
33
+ end
34
+
35
+ final_attrs
36
+ end
37
+ alias_method :to_hash, :to_h
38
+
39
+ def to_s
40
+ classes.to_s
41
+ end
42
+
43
+ def classes
44
+ self[:class]
45
+ end
46
+
47
+ def data
48
+ self[:data]
49
+ end
50
+
51
+ def stimulus
52
+ data.stimulus
53
+ end
54
+
55
+ def toggle(class_names)
56
+ classes.toggle(class_names)
57
+ self
58
+ end
59
+
60
+ def add(class_names)
61
+ classes.add(class_names)
62
+ self
63
+ end
64
+
65
+ def remove(class_names)
66
+ classes.remove(class_names)
67
+ self
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module Tailmix
6
+ module HTML
7
+ # Manages a set of CSS classes with a fluent, chainable API.
8
+ # Inherits from Set to ensure uniqueness and leverage its performance.
9
+ class ClassList < Set
10
+ # Initializes a new ClassList.
11
+ # @param initial_classes [String, Array, Set, nil] The initial classes to add.
12
+ def initialize(initial_classes = nil)
13
+ super()
14
+ add(initial_classes) if initial_classes
15
+ end
16
+
17
+ # Adds one or more classes. Handles strings, arrays, or other sets.
18
+ # This method is MUTABLE and chainable.
19
+ # @param class_names [String, Array, Set, nil]
20
+ # @return [self]
21
+ def add(class_names)
22
+ each_token(class_names) { |token| super(token) }
23
+ self
24
+ end
25
+ alias << add
26
+
27
+ # Removes one or more classes.
28
+ # This method is MUTABLE and chainable.
29
+ # @param class_names [String, Array, Set, nil]
30
+ # @return [self]
31
+ def remove(class_names)
32
+ each_token(class_names) { |token| delete(token) }
33
+ self
34
+ end
35
+
36
+ # Toggles one or more classes.
37
+ # This method is MUTABLE and chainable.
38
+ # @param class_names [String, Array, Set, nil]
39
+ # @return [self]
40
+ def toggle(class_names)
41
+ each_token(class_names) { |token| include?(token) ? delete(token) : add(token) }
42
+ self
43
+ end
44
+
45
+ # Returns a new ClassList with the given classes added. IMMUTABLE.
46
+ def added(class_names)
47
+ dup.add(class_names)
48
+ end
49
+
50
+ # Returns a new ClassList with the given classes removed. IMMUTABLE.
51
+ def removed(class_names)
52
+ dup.remove(class_names)
53
+ end
54
+
55
+ # Returns a new ClassList with the given classes toggled. IMMUTABLE.
56
+ def toggled(class_names)
57
+ dup.toggle(class_names)
58
+ end
59
+
60
+ # Renders the set of classes to a space-separated string for HTML.
61
+ # @return [String]
62
+ def to_s
63
+ to_a.join(" ")
64
+ end
65
+
66
+ private
67
+
68
+ # A robust way to iterate over tokens from various input types.
69
+ def each_token(input)
70
+ return unless input
71
+ # Convert Set/ClassList to array before splitting strings inside
72
+ items = input.is_a?(Set) ? input.to_a : Array(input)
73
+ items.each do |item|
74
+ item.to_s.split.each { |token| yield token unless token.empty? }
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "json"
5
+ require_relative "stimulus_builder"
6
+
7
+ module Tailmix
8
+ module HTML
9
+ class DataMap
10
+ MERGEABLE_LIST_ATTRIBUTES = %i[controller action target].freeze
11
+
12
+ def initialize(initial_data = {})
13
+ @data = {}
14
+ merge!(initial_data)
15
+ end
16
+
17
+ def stimulus
18
+ StimulusBuilder.new(self)
19
+ end
20
+
21
+ def merge!(other_data)
22
+ return self unless other_data
23
+ data_to_merge = other_data.is_a?(DataMap) ? other_data.instance_variable_get(:@data) : other_data
24
+
25
+ (data_to_merge || {}).each do |key, value|
26
+ key = key.to_sym
27
+ if value.is_a?(Hash) && @data[key].is_a?(Hash)
28
+ @data[key].merge!(value)
29
+ elsif MERGEABLE_LIST_ATTRIBUTES.include?(key)
30
+ add_to_set(key, value)
31
+ else
32
+ @data[key] = value
33
+ end
34
+ end
35
+ self
36
+ end
37
+ alias_method :add, :merge!
38
+
39
+ def merge(other_data)
40
+ dup.merge!(other_data)
41
+ end
42
+
43
+ def add_to_set(key, value)
44
+ @data[key] ||= Set.new
45
+ return unless value
46
+ items_to_process = value.is_a?(Set) ? value.to_a : Array(value)
47
+ items_to_process.each do |item|
48
+ item.to_s.split.each do |token|
49
+ @data[key].add(token) unless token.empty?
50
+ end
51
+ end
52
+ end
53
+
54
+ def remove(other_data)
55
+ (other_data || {}).each do |key, _|
56
+ @data.delete(key.to_sym)
57
+ end
58
+ self
59
+ end
60
+
61
+ def toggle(other_data)
62
+ (other_data || {}).each do |key, value|
63
+ key = key.to_sym
64
+ @data[key] == value ? @data.delete(key) : @data[key] = value
65
+ end
66
+ self
67
+ end
68
+
69
+ def to_h
70
+ flatten_data_hash(@data)
71
+ end
72
+
73
+ private
74
+
75
+ def flatten_data_hash(hash, prefix = "data", accumulator = {})
76
+ hash.each do |key, value|
77
+ current_key = "#{prefix}-#{key.to_s.tr('_', '-')}"
78
+ if key.to_s.end_with?("_value")
79
+ serialized_value = case value
80
+ when Hash, Array then value.to_json
81
+ else value
82
+ end
83
+ accumulator[current_key] = serialized_value
84
+ elsif value.is_a?(Hash)
85
+ flatten_data_hash(value, current_key, accumulator)
86
+ else
87
+ serialized_value = value.is_a?(Set) ? value.to_a.join(" ") : value
88
+ accumulator[current_key] = serialized_value unless serialized_value.to_s.empty?
89
+ end
90
+ end
91
+ accumulator
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module HTML
5
+ # A fluent DSL (builder) for constructing Stimulus data attributes.
6
+ # It acts as a proxy, modifying a DataMap instance directly.
7
+ class StimulusBuilder
8
+ def initialize(data_map)
9
+ @data_map = data_map
10
+ @context = nil # For context-aware attributes like targets and values
11
+ end
12
+
13
+ # Defines a controller and sets it as the current context.
14
+ # @return [self] for chaining.
15
+ def controller(controller_name)
16
+ @data_map.add_to_set(:controller, controller_name)
17
+ @context = controller_name.to_s
18
+ self
19
+ end
20
+
21
+ # Sets the controller context for subsequent calls.
22
+ def context(controller_name)
23
+ @context = controller_name.to_s
24
+ self
25
+ end
26
+
27
+ # Adds an action.
28
+ # @example
29
+ # .action("click->modal#open")
30
+ # @return [self]
31
+ def action(action_string)
32
+ @data_map.add_to_set(:action, action_string)
33
+ self
34
+ end
35
+
36
+ # Adds a target, scoped to the current controller context.
37
+ # @return [self]
38
+ def target(target_name)
39
+ ensure_context!
40
+ # `target` is a shared attribute, but names are scoped to a controller.
41
+ # So we add to the common `target` set.
42
+ @data_map.add_to_set(:"#{@context}-target", target_name)
43
+ self
44
+ end
45
+
46
+ # Adds a value, scoped to the current controller context.
47
+ # @return [self]
48
+ def value(value_name, value)
49
+ ensure_context!
50
+ @data_map.merge!("#{context_key(value_name)}_value" => value)
51
+ self
52
+ end
53
+
54
+ private
55
+
56
+ def ensure_context!
57
+ raise "A controller context must be set via .controller() or .context() before this call." unless @context
58
+ end
59
+
60
+ def context_key(name)
61
+ "#{@context}-#{name.to_s.tr('_', '-')}"
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ # Represents a callable action at runtime that can apply a set of
6
+ # predefined mutations to its context.
7
+ class Action
8
+ attr_reader :context, :definition
9
+
10
+ def initialize(context, action_name)
11
+ @context = context
12
+ @action_name = action_name.to_sym
13
+ @definition = context.definition.actions[@action_name]
14
+ raise Error, "Action `#{@action_name}` not found." unless @definition
15
+ end
16
+
17
+ # Applies the mutations to the context immutably, returning a new context.
18
+ # @return [Context] A new, modified context instance.
19
+ def apply
20
+ new_context = context.dup
21
+
22
+ action_on_clone = self.class.new(new_context, @action_name)
23
+
24
+ action_on_clone.apply!
25
+ end
26
+
27
+ def apply!
28
+ # `definition.mutations` { element_name => [commands] }
29
+ definition.mutations.each do |element_name, commands|
30
+ attributes_object = context.live_attributes_for(element_name)
31
+ next unless attributes_object
32
+
33
+ commands.each do |command|
34
+ target_field = attributes_object.public_send(command[:field])
35
+ target_field.public_send(command[:method], command[:payload])
36
+ end
37
+ end
38
+ context
39
+ end
40
+
41
+ # Serializes the action's definition into a hash for the JS bridge.
42
+ # @return [Hash]
43
+ def to_h
44
+ {
45
+ method: definition.action,
46
+ mutations: definition.mutations
47
+ }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ class Context
6
+ attr_reader :component_instance, :definition, :dimensions
7
+
8
+ def initialize(component_instance, definition, dimensions)
9
+ @component_instance = component_instance
10
+ @definition = definition
11
+ @dimensions = dimensions
12
+ @attributes_cache = {}
13
+ end
14
+
15
+ def initialize_copy(source)
16
+ super
17
+ @attributes_cache = source.instance_variable_get(:@attributes_cache).transform_values(&:dup)
18
+ end
19
+
20
+ def live_attributes_for(element_name)
21
+ @attributes_cache[element_name] ||= build_attributes_for(element_name, @dimensions)
22
+ end
23
+
24
+ def attributes_for(element_name, runtime_dimensions = {})
25
+ merged_dimensions = @dimensions.merge(runtime_dimensions)
26
+ return @attributes_cache[element_name] if merged_dimensions == @dimensions && @attributes_cache[element_name]
27
+
28
+ attributes_object = build_attributes_for(element_name, merged_dimensions)
29
+ @attributes_cache[element_name] = attributes_object if merged_dimensions == @dimensions
30
+ attributes_object
31
+ end
32
+
33
+ def action(name)
34
+ Action.new(self, name)
35
+ end
36
+
37
+ private
38
+
39
+ def build_attributes_for(element_name, dimensions)
40
+ element_def = @definition.elements.fetch(element_name)
41
+ initial_classes = element_def.attributes.classes
42
+ class_list = HTML::ClassList.new(initial_classes)
43
+
44
+ element_def.dimensions.each do |name, dim|
45
+ value = dimensions.fetch(name, dim[:default])
46
+ next if value.nil?
47
+ classes_for_option = dim.fetch(:options, {}).fetch(value, nil)
48
+ class_list.add(classes_for_option)
49
+ end
50
+
51
+ data_map = HTML::DataMap.new
52
+ Stimulus::Compiler.call(
53
+ definition: element_def.stimulus,
54
+ data_map: data_map,
55
+ root_definition: @definition,
56
+ component: @component_instance
57
+ )
58
+
59
+ HTML::Attributes.new(
60
+ { class: class_list, data: data_map },
61
+ element_name: element_def.name
62
+ )
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ class FacadeBuilder
6
+ def self.build(definition)
7
+ Class.new(Tailmix::Runtime::Context) do
8
+ definition.elements.each_key do |element_name|
9
+ define_method(element_name) do |runtime_dimensions = {}|
10
+ attributes_for(element_name, runtime_dimensions)
11
+ end
12
+ end
13
+
14
+ def inspect
15
+ component_name = @component_instance.class.name || "AnonymousComponent"
16
+ elements_list = @definition.elements.keys.join(", ")
17
+ "#<Tailmix::UI for #{component_name} elements=[#{elements_list}] dimensions=#{@dimensions.inspect}>"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ module Stimulus
6
+ class Compiler
7
+
8
+ def self.call(definition:, data_map:, root_definition:, component:)
9
+ (definition.definitions || []).each do |rule|
10
+ builder = data_map.stimulus
11
+
12
+ case rule[:type]
13
+ when :controller
14
+ builder.controller(rule[:name])
15
+ when :action
16
+ action_data = rule[:data]
17
+ controller_name = rule[:controller]
18
+
19
+ action_string = case action_data[:type]
20
+ when :raw
21
+ action_data[:content]
22
+ when :hash
23
+ action_data[:content].map { |event, method| "#{event}->#{controller_name}##{method}" }.join(" ")
24
+ when :tuple
25
+ event, method = action_data[:content]
26
+ "#{event}->#{controller_name}##{method}"
27
+ end
28
+
29
+ builder.context(controller_name).action(action_string)
30
+ when :target
31
+ builder.context(rule[:controller]).target(rule[:name])
32
+ when :value
33
+ source = rule[:source]
34
+
35
+ resolved_value = case source[:type]
36
+ when :literal
37
+ source[:content]
38
+ when :proc
39
+ source[:content].call
40
+ when :method
41
+ component.public_send(source[:content])
42
+ else
43
+ # type code here
44
+ end
45
+
46
+ builder.context(rule[:controller]).value(rule[:name], resolved_value)
47
+
48
+ when :param
49
+ builder.context(rule[:controller]).param(rule[:params])
50
+ when :action_payload
51
+ action = root_definition.actions.fetch(rule[:action_name])
52
+ builder.context(rule[:controller]).value(rule[:value_name], action.to_h)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require_relative "runtime/context"
5
+ require_relative "runtime/facade_builder"
6
+ require_relative "runtime/stimulus/compiler"
7
+ require_relative "html/attributes"
8
+ require_relative "runtime/action"
9
+
10
+
11
+ module Tailmix
12
+ module Runtime
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tailmix
4
- VERSION = "0.1.0"
4
+ VERSION = "0.4.5"
5
5
  end
data/lib/tailmix.rb CHANGED
@@ -1,37 +1,67 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "tailmix/version"
4
- require_relative "tailmix/schema"
5
- require_relative "tailmix/resolver"
6
- require_relative "tailmix/manager"
7
- require_relative "tailmix/part"
8
- require_relative "tailmix/dimension"
9
- require_relative "tailmix/element"
10
- require_relative "tailmix/utils"
4
+ require_relative "tailmix/definition"
5
+ require_relative "tailmix/runtime"
6
+ require_relative "tailmix/dev/tools"
11
7
 
12
8
  module Tailmix
13
- def self.included(base)
14
- base.extend(ClassMethods)
15
- base.instance_variable_set(:@tailmix_schema, nil)
9
+ class Error < StandardError; end
16
10
 
17
- base.define_singleton_method(:tailmix_schema) do
18
- @tailmix_schema
19
- end
11
+ class << self
12
+ attr_writer :configuration
13
+ end
14
+
15
+ def self.configuration
16
+ @configuration ||= Configuration.new
17
+ end
18
+
19
+ def self.configure
20
+ yield(configuration)
21
+ end
20
22
 
21
- base.define_singleton_method(:tailmix_schema=) do |value|
22
- @tailmix_schema = value
23
+ class Configuration
24
+ attr_accessor :element_selector_attribute
25
+
26
+ def initialize
27
+ element_selector_attribute = nil
23
28
  end
24
29
  end
25
30
 
26
31
  module ClassMethods
27
32
  def tailmix(&block)
28
- self.tailmix_schema = Schema.new(&block)
33
+ child_context = Definition::ContextBuilder.new
34
+ child_context.instance_eval(&block)
35
+ child_definition = child_context.build_definition
36
+
37
+ if superclass.respond_to?(:tailmix_definition) && (parent_definition = superclass.tailmix_definition)
38
+ @tailmix_definition = Definition::Merger.call(parent_definition, child_definition)
39
+ else
40
+ @tailmix_definition = child_definition
41
+ end
42
+ end
43
+
44
+ def tailmix_definition
45
+ @tailmix_definition || raise(Error, "Tailmix definition not found in #{name}")
46
+ end
47
+
48
+ def tailmix_facade_class
49
+ @_tailmix_facade_class ||= Runtime::FacadeBuilder.build(tailmix_definition)
50
+ end
51
+
52
+ def dev
53
+ Dev::Tools.new(self)
29
54
  end
30
55
  end
31
56
 
32
- private
57
+ def self.included(base)
58
+ base.extend(ClassMethods)
59
+ end
33
60
 
34
61
  def tailmix(options = {})
35
- Manager.new(self.class.tailmix_schema, options)
62
+ facade_class = self.class.tailmix_facade_class
63
+ facade_class.new(self, self.class.tailmix_definition, options)
36
64
  end
37
65
  end
66
+
67
+ require_relative "tailmix/engine" if defined?(Rails)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tailmix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Fokin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-14 00:00:00.000000000 Z
11
+ date: 2025-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -68,15 +68,38 @@ files:
68
68
  - LICENSE.txt
69
69
  - README.md
70
70
  - Rakefile
71
- - examples/status_badge_component.rb
71
+ - app/javascript/tailmix/finder.js
72
+ - app/javascript/tailmix/index.js
73
+ - app/javascript/tailmix/mutator.js
74
+ - app/javascript/tailmix/runner.js
75
+ - app/javascript/tailmix/stimulus_adapter.js
76
+ - examples/_modal_component.arb
77
+ - examples/modal_component.rb
78
+ - lib/generators/tailmix/install_generator.rb
72
79
  - lib/tailmix.rb
73
- - lib/tailmix/dimension.rb
74
- - lib/tailmix/element.rb
75
- - lib/tailmix/manager.rb
76
- - lib/tailmix/part.rb
77
- - lib/tailmix/resolver.rb
78
- - lib/tailmix/schema.rb
79
- - lib/tailmix/utils.rb
80
+ - lib/tailmix/definition.rb
81
+ - lib/tailmix/definition/context_builder.rb
82
+ - lib/tailmix/definition/contexts/action_builder.rb
83
+ - lib/tailmix/definition/contexts/actions/element_builder.rb
84
+ - lib/tailmix/definition/contexts/attribute_builder.rb
85
+ - lib/tailmix/definition/contexts/dimension_builder.rb
86
+ - lib/tailmix/definition/contexts/element_builder.rb
87
+ - lib/tailmix/definition/contexts/stimulus_builder.rb
88
+ - lib/tailmix/definition/merger.rb
89
+ - lib/tailmix/definition/result.rb
90
+ - lib/tailmix/dev/docs.rb
91
+ - lib/tailmix/dev/stimulus_generator.rb
92
+ - lib/tailmix/dev/tools.rb
93
+ - lib/tailmix/engine.rb
94
+ - lib/tailmix/html/attributes.rb
95
+ - lib/tailmix/html/class_list.rb
96
+ - lib/tailmix/html/data_map.rb
97
+ - lib/tailmix/html/stimulus_builder.rb
98
+ - lib/tailmix/runtime.rb
99
+ - lib/tailmix/runtime/action.rb
100
+ - lib/tailmix/runtime/context.rb
101
+ - lib/tailmix/runtime/facade_builder.rb
102
+ - lib/tailmix/runtime/stimulus/compiler.rb
80
103
  - lib/tailmix/version.rb
81
104
  - sig/tailmix.rbs
82
105
  homepage: https://github.com/alexander-s-f/tailmix