tailmix 0.4.7 → 0.4.8

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +46 -205
  4. data/app/javascript/tailmix/runtime/action_dispatcher.js +132 -0
  5. data/app/javascript/tailmix/runtime/component.js +130 -0
  6. data/app/javascript/tailmix/runtime/index.js +130 -0
  7. data/app/javascript/tailmix/runtime/plugins.js +35 -0
  8. data/app/javascript/tailmix/runtime/updater.js +140 -0
  9. data/docs/01_getting_started.md +0 -81
  10. data/examples/_modal_component.arb +17 -25
  11. data/examples/modal_component.rb +31 -155
  12. data/lib/tailmix/definition/builders/action_builder.rb +39 -0
  13. data/lib/tailmix/definition/{contexts → builders}/actions/element_builder.rb +1 -1
  14. data/lib/tailmix/definition/{contexts → builders}/attribute_builder.rb +1 -1
  15. data/lib/tailmix/definition/builders/component_builder.rb +81 -0
  16. data/lib/tailmix/definition/{contexts → builders}/dimension_builder.rb +2 -2
  17. data/lib/tailmix/definition/builders/element_builder.rb +83 -0
  18. data/lib/tailmix/definition/builders/reactor_builder.rb +43 -0
  19. data/lib/tailmix/definition/builders/rule_builder.rb +58 -0
  20. data/lib/tailmix/definition/builders/state_builder.rb +21 -0
  21. data/lib/tailmix/definition/{contexts → builders}/variant_builder.rb +17 -2
  22. data/lib/tailmix/definition/context_builder.rb +17 -12
  23. data/lib/tailmix/definition/payload_proxy.rb +16 -0
  24. data/lib/tailmix/definition/result.rb +17 -19
  25. data/lib/tailmix/dev/docs.rb +3 -9
  26. data/lib/tailmix/dev/tools.rb +0 -5
  27. data/lib/tailmix/dsl.rb +3 -5
  28. data/lib/tailmix/engine.rb +11 -1
  29. data/lib/tailmix/html/attributes.rb +22 -12
  30. data/lib/tailmix/middleware/registry_cleaner.rb +17 -0
  31. data/lib/tailmix/registry.rb +37 -0
  32. data/lib/tailmix/runtime/action_proxy.rb +29 -0
  33. data/lib/tailmix/runtime/attribute_builder.rb +102 -0
  34. data/lib/tailmix/runtime/attribute_cache.rb +23 -0
  35. data/lib/tailmix/runtime/context.rb +51 -62
  36. data/lib/tailmix/runtime/facade_builder.rb +8 -5
  37. data/lib/tailmix/runtime/state.rb +36 -0
  38. data/lib/tailmix/runtime/state_proxy.rb +34 -0
  39. data/lib/tailmix/runtime.rb +0 -1
  40. data/lib/tailmix/version.rb +1 -1
  41. data/lib/tailmix/view_helpers.rb +49 -0
  42. data/lib/tailmix.rb +4 -2
  43. metadata +26 -20
  44. data/app/javascript/tailmix/finder.js +0 -15
  45. data/app/javascript/tailmix/index.js +0 -7
  46. data/app/javascript/tailmix/mutator.js +0 -28
  47. data/app/javascript/tailmix/runner.js +0 -7
  48. data/app/javascript/tailmix/stimulus_adapter.js +0 -37
  49. data/docs/02_dsl_reference.md +0 -266
  50. data/docs/03_advanced_usage.md +0 -88
  51. data/docs/04_client_side_bridge.md +0 -119
  52. data/docs/05_cookbook.md +0 -249
  53. data/lib/tailmix/definition/contexts/action_builder.rb +0 -31
  54. data/lib/tailmix/definition/contexts/element_builder.rb +0 -55
  55. data/lib/tailmix/definition/contexts/stimulus_builder.rb +0 -101
  56. data/lib/tailmix/dev/stimulus_generator.rb +0 -124
  57. data/lib/tailmix/runtime/stimulus/compiler.rb +0 -59
@@ -3,16 +3,15 @@
3
3
  require "erb"
4
4
  require_relative "class_list"
5
5
  require_relative "data_map"
6
- require_relative "selector"
7
6
 
8
7
  module Tailmix
9
8
  module HTML
10
9
  class Attributes < Hash
11
- attr_reader :element_name, :variant_string
10
+ attr_reader :element_name
12
11
 
13
- def initialize(initial_hash = {}, element_name: nil, variant_string: "")
12
+ def initialize(initial_hash = {}, element_name: nil, context: nil)
14
13
  @element_name = element_name
15
- @variant_string = variant_string
14
+ @context = context
16
15
  super()
17
16
 
18
17
  attrs_to_merge = initial_hash.dup
@@ -24,24 +23,27 @@ module Tailmix
24
23
  self[:class] = ClassList.new(initial_classes)
25
24
  self[:data] = DataMap.new("data", initial_data || {})
26
25
  self[:aria] = DataMap.new("aria", initial_aria || {})
27
- self[:tailmix] = Selector.new(element_name, variant_string)
28
26
 
29
27
  merge!(attrs_to_merge)
30
28
  end
31
29
 
30
+
32
31
  def each(&block)
33
32
  to_h.each(&block)
34
33
  end
34
+ alias_method :each_pair, :each
35
35
 
36
36
  def to_h
37
- final_attrs = select { |k, _| !%i[class data aria tailmix].include?(k.to_sym) }
37
+ final_attrs = select { |k, _| !%i[class data aria].include?(k.to_sym) }
38
38
 
39
39
  class_string = self[:class].to_s
40
40
  final_attrs[:class] = class_string unless class_string.empty?
41
41
 
42
42
  final_attrs.merge!(self[:data].to_h)
43
43
  final_attrs.merge!(self[:aria].to_h)
44
- final_attrs.merge!(self[:tailmix].to_h)
44
+
45
+ final_attrs["data-tailmix-element"] = @element_name if @element_name
46
+ final_attrs["data-tailmix-id"] = @context.id if @context.id
45
47
 
46
48
  final_attrs
47
49
  end
@@ -67,10 +69,6 @@ module Tailmix
67
69
  data.stimulus
68
70
  end
69
71
 
70
- def tailmix
71
- self[:tailmix]
72
- end
73
-
74
72
  def toggle(class_names)
75
73
  classes.toggle(class_names)
76
74
  self
@@ -87,8 +85,20 @@ module Tailmix
87
85
  end
88
86
 
89
87
  def each_attribute(&block)
90
- [ classes: classes, data: data.to_h, aria: aria.to_h, tailmix: tailmix.to_h ].each(&block)
88
+ [ classes: classes, data: data.to_h, aria: aria.to_h ].each(&block)
89
+ end
90
+
91
+ def component
92
+ raise "No context available to build component root" unless @context
93
+
94
+ root_attrs = {
95
+ "data-tailmix-component" => @context.component_name,
96
+ "data-tailmix-state" => @context.state_payload,
97
+ }
98
+
99
+ self.class.new(self.to_h.merge(root_attrs), element_name: @element_name, context: @context)
91
100
  end
101
+ alias_method :root, :component
92
102
  end
93
103
  end
94
104
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Middleware
5
+ class RegistryCleaner
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ @app.call(env)
12
+ ensure
13
+ Tailmix::Registry.instance.clear!
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ require "singleton"
3
+ require "set"
4
+
5
+ module Tailmix
6
+ # A per-request registry to store unique component classes rendered
7
+ # during a request-response cycle.
8
+ class Registry
9
+ include Singleton
10
+
11
+ def initialize
12
+ @component_classes = Set.new
13
+ end
14
+
15
+ # Registers a component class.
16
+ # @param component_class [Class] The component class to register.
17
+ def register(component_class)
18
+ @component_classes.add(component_class)
19
+ end
20
+
21
+ # Gathers definitions from all registered classes.
22
+ # @return [Hash] A hash mapping component names to their definitions.
23
+ def definitions
24
+ @component_classes.each_with_object({}) do |klass, hash|
25
+ component_name = klass.name
26
+ if component_name && klass.respond_to?(:tailmix_definition)
27
+ hash[component_name] = klass.tailmix_definition.to_h
28
+ end
29
+ end
30
+ end
31
+
32
+ # Clears the registry. Must be called after each request.
33
+ def clear!
34
+ @component_classes.clear
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ # Proxy for convenient calling of actions (ui.action).
6
+ class ActionProxy
7
+ def initialize(context)
8
+ @context = context
9
+ end
10
+
11
+ def method_missing(method_name, *args, &block)
12
+ action_name = method_name.to_sym
13
+ action_def = @context.definition.actions[action_name]
14
+
15
+ unless action_def
16
+ raise NoMethodError, "undefined action `#{action_name}` for #{@context.component_name}"
17
+ end
18
+
19
+ # We return an object that can be called using .call.
20
+ # This allows you to write ui.action.save.call(payload)
21
+ ->(payload = {}) { @context.run_action(action_def, payload) }
22
+ end
23
+
24
+ def respond_to_missing?(method_name, include_private = false)
25
+ @context.definition.actions.key?(method_name.to_sym) || super
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ class AttributeBuilder
6
+ def initialize(element_def, state, context)
7
+ @element_def = element_def
8
+ @state = state
9
+ @context = context
10
+ end
11
+
12
+ def build
13
+ attributes = create_base_attributes
14
+
15
+ apply_dimensions(attributes)
16
+ apply_compound_variants(attributes)
17
+ apply_attribute_bindings(attributes)
18
+ apply_model_bindings(attributes)
19
+ apply_event_bindings(attributes)
20
+
21
+ attributes
22
+ end
23
+
24
+ private
25
+
26
+ def create_base_attributes
27
+ base_attrs = @element_def.default_attributes.merge(
28
+ class: @element_def.attributes.classes
29
+ )
30
+ HTML::Attributes.new(base_attrs, element_name: @element_def.name, context: @context)
31
+ end
32
+
33
+ # Applies classes and data/aria attributes from `dimension`.
34
+ def apply_dimensions(attributes)
35
+ @element_def.dimensions.each do |name, dim_def|
36
+ value = @state[name] || dim_def[:default]
37
+ next if value.nil?
38
+
39
+ variant_def = dim_def.fetch(:variants, {}).fetch(value, nil)
40
+
41
+ next unless variant_def
42
+ attributes.classes.add(variant_def.classes)
43
+ attributes.data.merge!(variant_def.data)
44
+ attributes.aria.merge!(variant_def.aria)
45
+ attributes.merge!(variant_def.attributes)
46
+ end
47
+ end
48
+
49
+ # Applies classes and data/aria attributes from `compound_variant`.
50
+ def apply_compound_variants(attributes)
51
+ @element_def.compound_variants.each do |cv|
52
+ next unless cv[:on].all? { |key, value| @state[key] == value }
53
+
54
+ modifications = cv[:modifications]
55
+ attributes.classes.add(modifications.classes)
56
+ attributes.data.merge!(modifications.data) if modifications.data
57
+ attributes.aria.merge!(modifications.aria) if modifications.aria
58
+ end
59
+ end
60
+
61
+ # Applies one-way attribute bindings (`bind :src, to: :url`).
62
+ def apply_attribute_bindings(attributes)
63
+ @element_def.attribute_bindings&.each do |attr_name, state_key_or_proc|
64
+ next if %i[text html].include?(attr_name)
65
+
66
+ value = if state_key_or_proc.is_a?(Proc)
67
+ state_key_or_proc.call(@state)
68
+ else
69
+ @state[state_key_or_proc]
70
+ end
71
+ attributes[attr_name] = value if value
72
+ end
73
+ end
74
+
75
+ # Applies two-way bindings (`model :value, to: :query`).
76
+ def apply_model_bindings(attributes)
77
+ @element_def.model_bindings&.each do |attr_name, binding_def|
78
+ state_key = binding_def[:state]
79
+ value = @state[state_key]
80
+ attributes[attr_name] = value if value
81
+
82
+ # We are adding data attributes that will "bring to life" the client-side JS.
83
+ attributes.data.add("tailmix-model-attr": attr_name)
84
+ attributes.data.add("tailmix-model-state": state_key)
85
+ attributes.data.add("tailmix-model-event": binding_def[:event])
86
+ attributes.data.add("tailmix-model-action": binding_def[:action]) if binding_def[:action]
87
+ end
88
+ end
89
+
90
+ # Applies event handlers (`on :click, :save`).
91
+ def apply_event_bindings(attributes)
92
+ return unless @element_def.event_bindings&.any?
93
+
94
+ action_string = @element_def.event_bindings.map { |b| "#{b[:event]}->#{b[:action]}" }.join(" ")
95
+ with_map = @element_def.event_bindings.map { |b| b[:with] }.compact.reduce({}, :merge)
96
+
97
+ attributes.data.add(tailmix_action: action_string)
98
+ attributes.data.add(tailmix_action_with: with_map.to_json) unless with_map.empty?
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ class AttributeCache
6
+ def initialize
7
+ @cache = {}
8
+ end
9
+
10
+ def get(element_name)
11
+ @cache[element_name.to_sym]
12
+ end
13
+
14
+ def set(element_name, attributes)
15
+ @cache[element_name.to_sym] = attributes
16
+ end
17
+
18
+ def clear!
19
+ @cache.clear
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,88 +1,77 @@
1
1
  # frozen_string_literal: true
2
+ require "json"
3
+ require_relative "../registry"
4
+ require_relative "state"
5
+ require_relative "state_proxy"
6
+ require_relative "action_proxy"
7
+ require_relative "attribute_cache"
8
+ require_relative "attribute_builder"
2
9
 
3
10
  module Tailmix
4
11
  module Runtime
5
12
  class Context
6
- attr_reader :component_instance, :definition, :dimensions
13
+ attr_reader :component_instance, :definition, :id, :state
7
14
 
8
- def initialize(component_instance, definition, dimensions)
15
+ def initialize(component_instance, definition, initial_state = {}, id: nil)
9
16
  @component_instance = component_instance
10
17
  @definition = definition
11
- @dimensions = dimensions
12
- @attributes_cache = {}
13
- end
18
+ @id = id
14
19
 
15
- def initialize_copy(source)
16
- super
17
- @attributes_cache = source.instance_variable_get(:@attributes_cache).transform_values(&:dup)
18
- end
20
+ @cache = AttributeCache.new
21
+ @state = State.new(definition.states, initial_state, cache: @cache)
19
22
 
20
- def live_attributes_for(element_name)
21
- @attributes_cache[element_name] ||= build_attributes_for(element_name, @dimensions)
23
+ Registry.instance.register(component_instance.class)
22
24
  end
23
25
 
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]
26
+ def state_proxy
27
+ @state_proxy ||= StateProxy.new(self)
28
+ end
27
29
 
28
- attributes_object = build_attributes_for(element_name, merged_dimensions)
29
- @attributes_cache[element_name] = attributes_object if merged_dimensions == @dimensions
30
- attributes_object
30
+ def action_proxy
31
+ @action_proxy ||= ActionProxy.new(self)
31
32
  end
32
33
 
33
- def action(name)
34
- Action.new(self, name)
34
+ def run_action(action_def, payload)
35
+ action_def.transitions.each do |transition|
36
+ # Here we simulate what JS does on the client.
37
+ case transition[:type]
38
+ when :set
39
+ # Processing PayloadProxy, if it exists.
40
+ value = transition[:payload][:value]
41
+ if value.is_a?(Hash) && value[:__type] == 'payload_value'
42
+ set_state(transition[:payload][:key], payload[value[:key]])
43
+ else
44
+ set_state(transition[:payload][:key], value)
45
+ end
46
+ when :toggle
47
+ key = transition[:payload][:key]
48
+ set_state(key, !get_state(key))
49
+ # `refresh` and `dispatch` are purely client-side operations; we ignore them on the server.
50
+ end
51
+ end
35
52
  end
36
53
 
37
- private
54
+ def attributes_for(element_name)
55
+ cached = @cache.get(element_name)
56
+ return cached if cached
38
57
 
39
- def build_attributes_for(element_name, dimensions)
40
58
  element_def = @definition.elements.fetch(element_name)
41
59
 
42
- active_dimensions = dimensions.slice(*element_def.dimensions.keys)
43
- variant_string = active_dimensions.map { |k, v| "#{k}:#{v}" }.join(",")
44
-
45
- attributes = HTML::Attributes.new(
46
- { class: element_def.attributes.classes },
47
- element_name: element_def.name,
48
- variant_string: variant_string,
49
- )
50
-
51
- element_def.dimensions.each do |name, dim_def|
52
- value = dimensions.fetch(name, dim_def[:default])
53
- next if value.nil?
54
-
55
- variant_def = dim_def.fetch(:variants, {}).fetch(value, nil)
56
- next unless variant_def
57
-
58
- attributes.classes.add(variant_def.classes)
59
- attributes.data.merge!(variant_def.data)
60
- attributes.aria.merge!(variant_def.aria)
61
- end
62
-
63
- element_def.compound_variants.each do |cv|
64
- conditions = cv[:on]
65
- modifications = cv[:modifications]
66
-
67
- match = conditions.all? do |key, value|
68
- dimensions[key] == value
69
- end
60
+ attributes = AttributeBuilder.new(element_def, @state, self).build
61
+ @cache.set(element_name, attributes)
62
+ attributes
63
+ end
70
64
 
71
- if match
72
- attributes.classes.add(modifications.classes)
73
- attributes.data.merge!(modifications.data)
74
- attributes.aria.merge!(modifications.aria)
75
- end
76
- end
65
+ def component_name
66
+ @component_instance.class.name
67
+ end
77
68
 
78
- Stimulus::Compiler.call(
79
- definition: element_def.stimulus,
80
- data_map: attributes.data,
81
- root_definition: @definition,
82
- component: @component_instance
83
- )
69
+ def state_payload
70
+ @state.to_h.to_json
71
+ end
84
72
 
85
- attributes
73
+ def definition_payload
74
+ @definition.to_h.to_json
86
75
  end
87
76
  end
88
77
  end
@@ -6,15 +6,18 @@ module Tailmix
6
6
  def self.build(definition)
7
7
  Class.new(Tailmix::Runtime::Context) do
8
8
  definition.elements.each_key do |element_name|
9
- define_method(element_name) do |runtime_dimensions = {}|
10
- attributes_for(element_name, runtime_dimensions)
9
+ define_method(element_name) do
10
+ attributes_for(element_name)
11
11
  end
12
12
  end
13
13
 
14
+ alias_method :state, :state_proxy
15
+ alias_method :action, :action_proxy
16
+
14
17
  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
+ # elements_list = @definition.elements.keys.join(", ")
19
+ # "#<Tailmix::UI for #{component_name} elements=[#{elements_list}] dimensions=#{@dimensions.inspect}>"
20
+ "#<Tailmix::UI for #{component_name} state=#{get_state.inspect}>"
18
21
  end
19
22
  end
20
23
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ class State
6
+ def initialize(state_definition, initial_values, cache:)
7
+ @definition = state_definition
8
+ @cache = cache
9
+ @data = initialize_data(initial_values)
10
+ end
11
+
12
+ def [](key)
13
+ @data[key.to_sym]
14
+ end
15
+
16
+ def []=(key, value)
17
+ return if @data[key.to_sym] == value
18
+
19
+ @data[key.to_sym] = value
20
+ # Main reactive trigger: when the state changes – we clear the cache!
21
+ @cache.clear!
22
+ end
23
+
24
+ def to_h
25
+ @data
26
+ end
27
+
28
+ private
29
+
30
+ def initialize_data(initial_values)
31
+ defaults = @definition.transform_values { |v| v[:default] }
32
+ defaults.merge(initial_values.transform_keys(&:to_sym))
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailmix
4
+ module Runtime
5
+ # Proxy for convenient access to the component state (ui.state).
6
+ class StateProxy
7
+ def initialize(context)
8
+ @context = context
9
+ end
10
+
11
+ def method_missing(method_name, *args, &block)
12
+ state_key = method_name.to_s.chomp("=").to_sym
13
+
14
+ # We are checking if this state is defined in the DSL.
15
+ unless @context.definition.states.key?(state_key)
16
+ raise NoMethodError, "undefined state `#{state_key}` for #{@context.component_name}"
17
+ end
18
+
19
+ if method_name.end_with?("=")
20
+ # This is a setter: ui.state.open = true
21
+ @context.set_state(state_key, args.first)
22
+ else
23
+ # This is a getter: ui.state.open
24
+ @context.get_state(state_key)
25
+ end
26
+ end
27
+
28
+ def respond_to_missing?(method_name, include_private = false)
29
+ state_key = method_name.to_s.chomp("=").to_sym
30
+ @context.definition.states.key?(state_key) || super
31
+ end
32
+ end
33
+ end
34
+ end
@@ -3,7 +3,6 @@
3
3
  require "set"
4
4
  require_relative "runtime/context"
5
5
  require_relative "runtime/facade_builder"
6
- require_relative "runtime/stimulus/compiler"
7
6
  require_relative "html/attributes"
8
7
  require_relative "runtime/action"
9
8
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tailmix
4
- VERSION = "0.4.7"
4
+ VERSION = "0.4.8"
5
5
  end
@@ -0,0 +1,49 @@
1
+ require "json"
2
+
3
+ module Tailmix
4
+ ##
5
+ # Provides helper methods for rendering Tailmix component definitions and managing
6
+ # Tailmix-related data attributes in view templates.
7
+ module ViewHelpers
8
+ # Renders a script tag containing the definitions for all unique
9
+ # Tailmix components used on the current page.
10
+ def tailmix_definitions_tag
11
+ definitions = Tailmix::Registry.instance.definitions
12
+ return if definitions.empty?
13
+
14
+ json_payload = definitions.to_json
15
+
16
+ tag.script(
17
+ type: "application/json",
18
+ "data-tailmix-definitions": "true"
19
+ ) do
20
+ json_payload.html_safe
21
+ end
22
+ end
23
+
24
+ # Generates a hash of attributes for an external trigger that will control a named component instance.
25
+ #
26
+ # @param target_id [String, Symbol] Target component ID.
27
+ # @param action_name [String, Symbol] The name of the action to be called.
28
+ # @param options [Hash]
29
+ # @return [Hash]
30
+ def tailmix_trigger_for(target_id, action_name, options = {})
31
+ # target_id = options.fetch(:target_id)
32
+ # action_name = options.fetch(:action_name)
33
+
34
+ event_name = options.fetch(:event_name, :click)
35
+ with = options.fetch(:with, nil)
36
+
37
+ attributes = {
38
+ "data-tailmix-trigger-for" => target_id.to_s,
39
+ "data-tailmix-action" => "#{event_name}->#{action_name}"
40
+ }
41
+
42
+ if with
43
+ attributes["data-tailmix-action-payload"] = with.to_json
44
+ end
45
+
46
+ attributes
47
+ end
48
+ end
49
+ end
data/lib/tailmix.rb CHANGED
@@ -5,6 +5,8 @@ require_relative "tailmix/configuration"
5
5
  require_relative "tailmix/dsl"
6
6
  require_relative "tailmix/definition"
7
7
  require_relative "tailmix/runtime"
8
+ require_relative "tailmix/middleware/registry_cleaner"
9
+ require_relative "tailmix/view_helpers"
8
10
 
9
11
  module Tailmix
10
12
  class Error < StandardError; end
@@ -25,8 +27,8 @@ module Tailmix
25
27
  base.extend(DSL)
26
28
  end
27
29
 
28
- def tailmix(dimensions = {})
29
- self.class.tailmix_facade_class.new(self, self.class.tailmix_definition, dimensions)
30
+ def tailmix(id: nil, **initial_state)
31
+ self.class.tailmix_facade_class.new(self, self.class.tailmix_definition, initial_state, id: id)
30
32
  end
31
33
  end
32
34