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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +46 -205
- data/app/javascript/tailmix/runtime/action_dispatcher.js +132 -0
- data/app/javascript/tailmix/runtime/component.js +130 -0
- data/app/javascript/tailmix/runtime/index.js +130 -0
- data/app/javascript/tailmix/runtime/plugins.js +35 -0
- data/app/javascript/tailmix/runtime/updater.js +140 -0
- data/docs/01_getting_started.md +0 -81
- data/examples/_modal_component.arb +17 -25
- data/examples/modal_component.rb +31 -155
- data/lib/tailmix/definition/builders/action_builder.rb +39 -0
- data/lib/tailmix/definition/{contexts → builders}/actions/element_builder.rb +1 -1
- data/lib/tailmix/definition/{contexts → builders}/attribute_builder.rb +1 -1
- data/lib/tailmix/definition/builders/component_builder.rb +81 -0
- data/lib/tailmix/definition/{contexts → builders}/dimension_builder.rb +2 -2
- data/lib/tailmix/definition/builders/element_builder.rb +83 -0
- data/lib/tailmix/definition/builders/reactor_builder.rb +43 -0
- data/lib/tailmix/definition/builders/rule_builder.rb +58 -0
- data/lib/tailmix/definition/builders/state_builder.rb +21 -0
- data/lib/tailmix/definition/{contexts → builders}/variant_builder.rb +17 -2
- data/lib/tailmix/definition/context_builder.rb +17 -12
- data/lib/tailmix/definition/payload_proxy.rb +16 -0
- data/lib/tailmix/definition/result.rb +17 -19
- data/lib/tailmix/dev/docs.rb +3 -9
- data/lib/tailmix/dev/tools.rb +0 -5
- data/lib/tailmix/dsl.rb +3 -5
- data/lib/tailmix/engine.rb +11 -1
- data/lib/tailmix/html/attributes.rb +22 -12
- data/lib/tailmix/middleware/registry_cleaner.rb +17 -0
- data/lib/tailmix/registry.rb +37 -0
- data/lib/tailmix/runtime/action_proxy.rb +29 -0
- data/lib/tailmix/runtime/attribute_builder.rb +102 -0
- data/lib/tailmix/runtime/attribute_cache.rb +23 -0
- data/lib/tailmix/runtime/context.rb +51 -62
- data/lib/tailmix/runtime/facade_builder.rb +8 -5
- data/lib/tailmix/runtime/state.rb +36 -0
- data/lib/tailmix/runtime/state_proxy.rb +34 -0
- data/lib/tailmix/runtime.rb +0 -1
- data/lib/tailmix/version.rb +1 -1
- data/lib/tailmix/view_helpers.rb +49 -0
- data/lib/tailmix.rb +4 -2
- metadata +26 -20
- data/app/javascript/tailmix/finder.js +0 -15
- data/app/javascript/tailmix/index.js +0 -7
- data/app/javascript/tailmix/mutator.js +0 -28
- data/app/javascript/tailmix/runner.js +0 -7
- data/app/javascript/tailmix/stimulus_adapter.js +0 -37
- data/docs/02_dsl_reference.md +0 -266
- data/docs/03_advanced_usage.md +0 -88
- data/docs/04_client_side_bridge.md +0 -119
- data/docs/05_cookbook.md +0 -249
- data/lib/tailmix/definition/contexts/action_builder.rb +0 -31
- data/lib/tailmix/definition/contexts/element_builder.rb +0 -55
- data/lib/tailmix/definition/contexts/stimulus_builder.rb +0 -101
- data/lib/tailmix/dev/stimulus_generator.rb +0 -124
- data/lib/tailmix/runtime/stimulus/compiler.rb +0 -59
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_relative "../payload_proxy"
|
|
3
|
+
|
|
4
|
+
module Tailmix
|
|
5
|
+
module Definition
|
|
6
|
+
module Builders
|
|
7
|
+
class ActionBuilder
|
|
8
|
+
def initialize
|
|
9
|
+
@transitions = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def set(state_key, value)
|
|
13
|
+
processed_value = if value.is_a?(PayloadValue)
|
|
14
|
+
{ __type: 'payload_value', key: value.key }
|
|
15
|
+
else
|
|
16
|
+
value
|
|
17
|
+
end
|
|
18
|
+
@transitions << { type: :set, payload: { key: state_key.to_sym, value: processed_value } }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def toggle(state_key)
|
|
22
|
+
@transitions << { type: :toggle, payload: { key: state_key.to_sym } }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def refresh(state_key, params: {})
|
|
26
|
+
@transitions << { type: :refresh, payload: { key: state_key.to_sym, params: params } }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def dispatch(event_name, detail: {})
|
|
30
|
+
@transitions << { type: :dispatch, payload: { name: event_name, detail: detail } }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def build_definition
|
|
34
|
+
Result::Action.new(transitions: @transitions.freeze)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "action_builder"
|
|
4
|
+
require_relative "element_builder"
|
|
5
|
+
require_relative "reactor_builder"
|
|
6
|
+
require_relative "../payload_proxy"
|
|
7
|
+
|
|
8
|
+
module Tailmix
|
|
9
|
+
module Definition
|
|
10
|
+
module Builders
|
|
11
|
+
class ComponentBuilder
|
|
12
|
+
attr_reader :component_name
|
|
13
|
+
|
|
14
|
+
def initialize(component_name:)
|
|
15
|
+
@states = {}
|
|
16
|
+
@actions = {}
|
|
17
|
+
@elements = {}
|
|
18
|
+
@component_name = component_name
|
|
19
|
+
@plugins = {}
|
|
20
|
+
@reactions = {}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def state(name, default: nil, endpoint: nil, toggle: false)
|
|
24
|
+
@states[name.to_sym] = { default: default, endpoint: endpoint }.compact
|
|
25
|
+
if toggle
|
|
26
|
+
action_name = :"toggle_#{name}"
|
|
27
|
+
action(action_name) { toggle name }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def action(name, &block)
|
|
32
|
+
builder = ActionBuilder.new
|
|
33
|
+
builder.instance_exec(PayloadProxy.new, &block)
|
|
34
|
+
@actions[name.to_sym] = builder
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def element(name, classes = "", &block)
|
|
38
|
+
builder = ElementBuilder.new(name)
|
|
39
|
+
builder.attributes.classes(classes.split)
|
|
40
|
+
builder.instance_eval(&block) if block
|
|
41
|
+
@elements[name.to_sym] = builder
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def plugin(name, options = {})
|
|
45
|
+
plugin_name = name.to_s.gsub(/_([a-z])/) { $1.upcase }
|
|
46
|
+
@plugins[plugin_name] = options
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def react(on:, run: nil, **options, &block)
|
|
50
|
+
watched_states = Array(on)
|
|
51
|
+
|
|
52
|
+
# Processing the short form: `react on: :query, run: :search`
|
|
53
|
+
if run
|
|
54
|
+
builder = ReactorBuilder.new(watched_states.first)
|
|
55
|
+
builder.run(run, **options)
|
|
56
|
+
watched_states.each { |state| (@reactions[state] ||= []).concat(builder.build_rules) }
|
|
57
|
+
return
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Processing the full form with the block.
|
|
61
|
+
if block
|
|
62
|
+
builder = ReactorBuilder.new(watched_states.first)
|
|
63
|
+
builder.instance_eval(&block) # `instance_eval` чтобы не писать `r.`
|
|
64
|
+
watched_states.each { |state| (@reactions[state] ||= []).concat(builder.build_rules) }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def build_definition
|
|
69
|
+
Result::Context.new(
|
|
70
|
+
name: component_name,
|
|
71
|
+
states: @states.freeze,
|
|
72
|
+
actions: @actions.transform_values(&:build_definition).freeze,
|
|
73
|
+
elements: @elements.transform_values(&:build_definition).freeze,
|
|
74
|
+
reactions: @reactions.freeze,
|
|
75
|
+
plugins: @plugins.freeze
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -4,7 +4,7 @@ require_relative "variant_builder"
|
|
|
4
4
|
|
|
5
5
|
module Tailmix
|
|
6
6
|
module Definition
|
|
7
|
-
module
|
|
7
|
+
module Builders
|
|
8
8
|
class DimensionBuilder
|
|
9
9
|
def initialize(default: nil)
|
|
10
10
|
@variants = {}
|
|
@@ -13,12 +13,12 @@ module Tailmix
|
|
|
13
13
|
|
|
14
14
|
def variant(name, classes = "", data: {}, aria: {}, &block)
|
|
15
15
|
builder = VariantBuilder.new
|
|
16
|
+
|
|
16
17
|
builder.classes(classes) if classes && !classes.empty?
|
|
17
18
|
builder.data(data)
|
|
18
19
|
builder.aria(aria)
|
|
19
20
|
|
|
20
21
|
builder.instance_eval(&block) if block
|
|
21
|
-
|
|
22
22
|
@variants[name] = builder.build_variant
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "attribute_builder"
|
|
4
|
+
require_relative "dimension_builder"
|
|
5
|
+
require_relative "variant_builder"
|
|
6
|
+
|
|
7
|
+
module Tailmix
|
|
8
|
+
module Definition
|
|
9
|
+
module Builders
|
|
10
|
+
class ElementBuilder
|
|
11
|
+
def initialize(name)
|
|
12
|
+
@name = name
|
|
13
|
+
@default_attributes = {}
|
|
14
|
+
@dimensions = {}
|
|
15
|
+
@compound_variants = []
|
|
16
|
+
@event_bindings = []
|
|
17
|
+
@attribute_bindings = {}
|
|
18
|
+
@model_bindings = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def attributes
|
|
22
|
+
@attributes_builder ||= AttributeBuilder.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def method_missing(name, *args, &block)
|
|
26
|
+
attribute_name = name.to_s.chomp("=").to_sym
|
|
27
|
+
@default_attributes[attribute_name] = args.first
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def respond_to_missing?(*_args)
|
|
31
|
+
true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def on(event_name, action_name, with: nil, **options)
|
|
35
|
+
# `with` mapping: `{ payload_key => state_key }`
|
|
36
|
+
@event_bindings << { event: event_name, action: action_name, with: with, options: options }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def bind(attribute_name, to:)
|
|
40
|
+
@attribute_bindings[attribute_name.to_sym] = to.to_sym
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def model(attribute_name, to:, on: :input, action: nil, debounce: nil)
|
|
44
|
+
@model_bindings[attribute_name.to_sym] = {
|
|
45
|
+
state: to.to_sym,
|
|
46
|
+
event: on,
|
|
47
|
+
action: action,
|
|
48
|
+
debounce: debounce
|
|
49
|
+
}.compact
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def dimension(name, &block)
|
|
53
|
+
builder = DimensionBuilder.new
|
|
54
|
+
builder.instance_eval(&block)
|
|
55
|
+
@dimensions[name.to_sym] = builder.build_dimension
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def compound_variant(on:, &block)
|
|
59
|
+
builder = VariantBuilder.new
|
|
60
|
+
builder.instance_eval(&block)
|
|
61
|
+
|
|
62
|
+
@compound_variants << {
|
|
63
|
+
on: on,
|
|
64
|
+
modifications: builder.build_variant
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def build_definition
|
|
69
|
+
Result::Element.new(
|
|
70
|
+
name: @name,
|
|
71
|
+
attributes: attributes.build_definition,
|
|
72
|
+
default_attributes: @default_attributes.freeze,
|
|
73
|
+
dimensions: @dimensions.freeze,
|
|
74
|
+
compound_variants: @compound_variants.freeze,
|
|
75
|
+
event_bindings: @event_bindings.freeze,
|
|
76
|
+
attribute_bindings: @attribute_bindings.freeze,
|
|
77
|
+
model_bindings: @model_bindings.freeze
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_relative "rule_builder"
|
|
3
|
+
|
|
4
|
+
module Tailmix
|
|
5
|
+
module Definition
|
|
6
|
+
module Builders
|
|
7
|
+
class ReactorBuilder
|
|
8
|
+
def initialize(watched_state)
|
|
9
|
+
@watched_state = watched_state
|
|
10
|
+
@rules = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Start a method for the rule chain: r.value("commercial")
|
|
14
|
+
def value(expected_value)
|
|
15
|
+
rule_builder = RuleBuilder.new(@watched_state)
|
|
16
|
+
rule_builder.value(expected_value)
|
|
17
|
+
@rules << rule_builder
|
|
18
|
+
rule_builder
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Alternative startup method: r.state(:zip_code)
|
|
22
|
+
def state(state_key)
|
|
23
|
+
rule_builder = RuleBuilder.new(state_key)
|
|
24
|
+
@rules << rule_builder
|
|
25
|
+
rule_builder
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Unconditional effect (always triggers on change)
|
|
29
|
+
def run(action_name, with: nil)
|
|
30
|
+
# We create an "empty" rule with a condition that is always true.
|
|
31
|
+
rule_builder = RuleBuilder.new(nil)
|
|
32
|
+
rule_builder.instance_variable_set(:@rule, { condition: { type: :always_true } })
|
|
33
|
+
rule_builder.run(action_name, with: with)
|
|
34
|
+
@rules << rule_builder
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def build_rules
|
|
38
|
+
@rules.map(&:build_rule)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tailmix
|
|
4
|
+
module Definition
|
|
5
|
+
module Builders
|
|
6
|
+
class RuleBuilder
|
|
7
|
+
def initialize(source_state_key)
|
|
8
|
+
@rule = { condition: { type: :eql, source: { type: :state, key: source_state_key } } }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def value(expected_value)
|
|
12
|
+
@rule[:condition][:value] = expected_value
|
|
13
|
+
self
|
|
14
|
+
end
|
|
15
|
+
alias_method :is, :value
|
|
16
|
+
|
|
17
|
+
def is_not(expected_value)
|
|
18
|
+
@rule[:condition][:type] = :not_eql
|
|
19
|
+
@rule[:condition][:value] = expected_value
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def is_truthy
|
|
24
|
+
@rule[:condition][:type] = :truthy
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def set_state(payload)
|
|
29
|
+
add_effect(:set_state, payload: payload)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def run(action_name, with: nil)
|
|
33
|
+
add_effect(:run_action, name: action_name, with: with)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def dispatch(event_name, detail: {})
|
|
37
|
+
add_effect(:dispatch_event, name: event_name, detail: detail)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def call(element_name, method_name, *args)
|
|
41
|
+
add_effect(:call_method, element: element_name, method: method_name, args: args)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def build_rule
|
|
45
|
+
@rule
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def add_effect(type, **payload)
|
|
51
|
+
@rule[:effects] ||= []
|
|
52
|
+
@rule[:effects] << { type: type, payload: payload }
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tailmix
|
|
4
|
+
module Definition
|
|
5
|
+
module Builders
|
|
6
|
+
class StateBuilder
|
|
7
|
+
def initialize
|
|
8
|
+
@data_source = {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def endpoint(method, url:)
|
|
12
|
+
@data_source = { method: method, url: url }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def build_data_source
|
|
16
|
+
@data_source.empty? ? nil : @data_source.freeze
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module Tailmix
|
|
4
4
|
module Definition
|
|
5
|
-
module
|
|
5
|
+
module Builders
|
|
6
6
|
class VariantBuilder
|
|
7
7
|
def initialize
|
|
8
8
|
@class_groups = []
|
|
9
9
|
@data = {}
|
|
10
10
|
@aria = {}
|
|
11
|
+
@attributes = {}
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def classes(class_string, options = {})
|
|
@@ -22,11 +23,25 @@ module Tailmix
|
|
|
22
23
|
@aria.merge!(hash)
|
|
23
24
|
end
|
|
24
25
|
|
|
26
|
+
def method_missing(name, *args, &block)
|
|
27
|
+
# `disabled true` -> { disabled: true }
|
|
28
|
+
# `placeholder "text"` -> { placeholder: "text" }
|
|
29
|
+
# `type "password"` -> { type: "password" }
|
|
30
|
+
attribute_name = name.to_s.chomp("=").to_sym
|
|
31
|
+
value = args.first
|
|
32
|
+
@attributes[attribute_name] = value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def respond_to_missing?(*_args)
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
|
|
25
39
|
def build_variant
|
|
26
40
|
Definition::Result::Variant.new(
|
|
27
41
|
class_groups: @class_groups.freeze,
|
|
28
42
|
data: @data.freeze,
|
|
29
|
-
aria: @aria.freeze
|
|
43
|
+
aria: @aria.freeze,
|
|
44
|
+
attributes: @attributes.freeze
|
|
30
45
|
)
|
|
31
46
|
end
|
|
32
47
|
end
|
|
@@ -1,36 +1,41 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "
|
|
4
|
-
require_relative "
|
|
5
|
-
require_relative "
|
|
3
|
+
require_relative "builders/action_builder"
|
|
4
|
+
require_relative "builders/element_builder"
|
|
5
|
+
require_relative "builders/variant_builder"
|
|
6
|
+
require_relative "payload_proxy"
|
|
6
7
|
|
|
7
8
|
module Tailmix
|
|
8
9
|
module Definition
|
|
9
10
|
class ContextBuilder
|
|
10
|
-
attr_reader :elements, :actions
|
|
11
|
+
attr_reader :elements, :actions, :component_name
|
|
11
12
|
|
|
12
|
-
def initialize
|
|
13
|
+
def initialize(component_name:)
|
|
13
14
|
@elements = {}
|
|
14
15
|
@actions = {}
|
|
16
|
+
@component_name = component_name
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
def element(name,
|
|
18
|
-
builder =
|
|
19
|
-
builder.attributes.classes(
|
|
19
|
+
def element(name, classes = "", &block)
|
|
20
|
+
builder = Builders::ElementBuilder.new(name)
|
|
21
|
+
builder.attributes.classes(classes.split)
|
|
20
22
|
|
|
21
23
|
builder.instance_eval(&block) if block
|
|
22
|
-
|
|
23
24
|
@elements[name.to_sym] = builder
|
|
25
|
+
|
|
26
|
+
@actions.merge!(builder.auto_actions)
|
|
24
27
|
end
|
|
25
28
|
|
|
26
|
-
def action(name,
|
|
27
|
-
builder =
|
|
28
|
-
|
|
29
|
+
def action(name, &block)
|
|
30
|
+
builder = Builders::ActionBuilder.new
|
|
31
|
+
proxy = Builders::PayloadProxy.new
|
|
32
|
+
builder.instance_exec(proxy, &block)
|
|
29
33
|
@actions[name.to_sym] = builder
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
def build_definition
|
|
33
37
|
Definition::Result::Context.new(
|
|
38
|
+
name: component_name,
|
|
34
39
|
elements: @elements.transform_values(&:build_definition).freeze,
|
|
35
40
|
actions: @actions.transform_values(&:build_definition).freeze,
|
|
36
41
|
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tailmix
|
|
4
|
+
module Definition
|
|
5
|
+
# A marker indicating that the value should be taken from the runtime payload.
|
|
6
|
+
PayloadValue = Struct.new(:key)
|
|
7
|
+
|
|
8
|
+
# A proxy object that is passed to the `action do |payload|` block.
|
|
9
|
+
# It creates PayloadValue markers instead of containing the actual data.
|
|
10
|
+
class PayloadProxy
|
|
11
|
+
def [](key)
|
|
12
|
+
PayloadValue.new(key.to_sym)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -3,20 +3,25 @@
|
|
|
3
3
|
module Tailmix
|
|
4
4
|
module Definition
|
|
5
5
|
module Result
|
|
6
|
-
Context = Struct.new(:
|
|
6
|
+
Context = Struct.new(:name, :states, :actions, :elements, :plugins, :reactions, keyword_init: true) do
|
|
7
7
|
def to_h
|
|
8
8
|
{
|
|
9
|
-
|
|
9
|
+
name: name,
|
|
10
|
+
states: states,
|
|
10
11
|
actions: actions.transform_values(&:to_h),
|
|
12
|
+
elements: elements.transform_values(&:to_h),
|
|
13
|
+
plugins: plugins,
|
|
14
|
+
reactions: reactions
|
|
11
15
|
}
|
|
12
16
|
end
|
|
13
17
|
end
|
|
14
18
|
|
|
15
|
-
Element = Struct.new(:name, :attributes, :dimensions, :
|
|
19
|
+
Element = Struct.new(:name, :attributes, :dimensions, :compound_variants, :event_bindings, :attribute_bindings, :model_bindings, :default_attributes, keyword_init: true) do
|
|
16
20
|
def to_h
|
|
17
21
|
{
|
|
18
22
|
name: name,
|
|
19
23
|
attributes: attributes.to_h,
|
|
24
|
+
default_attributes: default_attributes,
|
|
20
25
|
dimensions: dimensions.transform_values do |dimension|
|
|
21
26
|
dimension.transform_values do |value|
|
|
22
27
|
case value
|
|
@@ -29,13 +34,14 @@ module Tailmix
|
|
|
29
34
|
end
|
|
30
35
|
end
|
|
31
36
|
end,
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
compound_variants: compound_variants,
|
|
38
|
+
attribute_bindings: attribute_bindings,
|
|
39
|
+
model_bindings: model_bindings,
|
|
34
40
|
}
|
|
35
41
|
end
|
|
36
42
|
end
|
|
37
43
|
|
|
38
|
-
Variant = Struct.new(:class_groups, :data, :aria, keyword_init: true) do
|
|
44
|
+
Variant = Struct.new(:class_groups, :data, :aria, :attributes, keyword_init: true) do
|
|
39
45
|
def classes
|
|
40
46
|
class_groups.flat_map { |group| group[:classes] }
|
|
41
47
|
end
|
|
@@ -45,7 +51,8 @@ module Tailmix
|
|
|
45
51
|
classes: classes,
|
|
46
52
|
class_groups: class_groups,
|
|
47
53
|
data: data,
|
|
48
|
-
aria: aria
|
|
54
|
+
aria: aria,
|
|
55
|
+
attributes: attributes
|
|
49
56
|
}
|
|
50
57
|
end
|
|
51
58
|
end
|
|
@@ -58,22 +65,13 @@ module Tailmix
|
|
|
58
65
|
end
|
|
59
66
|
end
|
|
60
67
|
|
|
61
|
-
|
|
62
|
-
def to_h
|
|
63
|
-
{
|
|
64
|
-
definitions: definitions
|
|
65
|
-
}
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
Action = Struct.new(:action, :mutations, keyword_init: true) do
|
|
68
|
+
Action = Struct.new(:transitions, keyword_init: true) do
|
|
70
69
|
def to_h
|
|
71
70
|
{
|
|
72
|
-
|
|
73
|
-
mutations: mutations
|
|
71
|
+
transitions: transitions,
|
|
74
72
|
}
|
|
75
73
|
end
|
|
76
74
|
end
|
|
77
75
|
end
|
|
78
76
|
end
|
|
79
|
-
end
|
|
77
|
+
end
|
data/lib/tailmix/dev/docs.rb
CHANGED
|
@@ -18,12 +18,8 @@ module Tailmix
|
|
|
18
18
|
output << ""
|
|
19
19
|
|
|
20
20
|
output << generate_dimensions_docs
|
|
21
|
-
output <<
|
|
22
|
-
output << generate_compound_variants_docs # <-- Наш новый метод
|
|
23
|
-
output << ""
|
|
21
|
+
output << generate_compound_variants_docs
|
|
24
22
|
output << generate_actions_docs
|
|
25
|
-
output << ""
|
|
26
|
-
output << generate_stimulus_docs
|
|
27
23
|
|
|
28
24
|
output.join("\n")
|
|
29
25
|
end
|
|
@@ -70,6 +66,7 @@ module Tailmix
|
|
|
70
66
|
end
|
|
71
67
|
|
|
72
68
|
if compound_variants_by_element.any?
|
|
69
|
+
output << ""
|
|
73
70
|
output << "Compound Variants:"
|
|
74
71
|
compound_variants_by_element.each do |element|
|
|
75
72
|
output << " - on element `:#{element.name}`:"
|
|
@@ -86,6 +83,7 @@ module Tailmix
|
|
|
86
83
|
output << " - aria: #{modifications.aria.inspect}" if modifications.aria.any?
|
|
87
84
|
end
|
|
88
85
|
end
|
|
86
|
+
output << ""
|
|
89
87
|
end
|
|
90
88
|
|
|
91
89
|
output.join("\n")
|
|
@@ -107,10 +105,6 @@ module Tailmix
|
|
|
107
105
|
output.join("\n")
|
|
108
106
|
end
|
|
109
107
|
|
|
110
|
-
def generate_stimulus_docs
|
|
111
|
-
@tools.stimulus.scaffold(show_docs: true)
|
|
112
|
-
end
|
|
113
|
-
|
|
114
108
|
def all_dimensions
|
|
115
109
|
@_all_dimensions ||= @definition.elements.values.flat_map(&:dimensions).reduce({}, :merge)
|
|
116
110
|
end
|
data/lib/tailmix/dev/tools.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "stimulus_generator"
|
|
4
3
|
require_relative "docs"
|
|
5
4
|
|
|
6
5
|
module Tailmix
|
|
@@ -18,10 +17,6 @@ module Tailmix
|
|
|
18
17
|
end
|
|
19
18
|
alias_method :help, :docs
|
|
20
19
|
|
|
21
|
-
def stimulus
|
|
22
|
-
StimulusGenerator.new(@definition, @component_class.name)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
20
|
def elements
|
|
26
21
|
@definition.elements.values.map(&:name)
|
|
27
22
|
end
|
data/lib/tailmix/dsl.rb
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "definition/
|
|
3
|
+
require_relative "definition/builders/component_builder"
|
|
4
4
|
require_relative "definition/merger"
|
|
5
5
|
require_relative "dev/tools"
|
|
6
6
|
|
|
7
7
|
module Tailmix
|
|
8
|
-
# The main DSL for defining component styles and behaviors.
|
|
9
|
-
# This module is extended into any class that includes Tailmix.
|
|
10
8
|
module DSL
|
|
11
9
|
def tailmix(&block)
|
|
12
|
-
child_context = Definition::
|
|
10
|
+
child_context = Definition::Builders::ComponentBuilder.new(component_name: self)
|
|
13
11
|
child_context.instance_eval(&block)
|
|
14
12
|
child_definition = child_context.build_definition
|
|
15
13
|
|
|
@@ -32,4 +30,4 @@ module Tailmix
|
|
|
32
30
|
Dev::Tools.new(self)
|
|
33
31
|
end
|
|
34
32
|
end
|
|
35
|
-
end
|
|
33
|
+
end
|
data/lib/tailmix/engine.rb
CHANGED
|
@@ -6,12 +6,22 @@ module Tailmix
|
|
|
6
6
|
Rails.application.config.assets.paths << Engine.root.join("app/javascript")
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
PRECOMPILE_ASSETS = %w[
|
|
9
|
+
PRECOMPILE_ASSETS = %w[ runtime/action_dispatcher.js runtime/component.js runtime/updater.js runtime/index.js runtime/plugins.js ]
|
|
10
10
|
|
|
11
11
|
initializer "tailmix.assets" do
|
|
12
12
|
if Rails.application.config.respond_to?(:assets)
|
|
13
13
|
Rails.application.config.assets.precompile += PRECOMPILE_ASSETS
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
|
+
|
|
17
|
+
initializer "tailmix.add_middleware" do |app|
|
|
18
|
+
app.middleware.use Tailmix::Middleware::RegistryCleaner
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
initializer "tailmix.helpers" do
|
|
22
|
+
ActiveSupport.on_load(:action_controller_base) do
|
|
23
|
+
helper Tailmix::ViewHelpers
|
|
24
|
+
end
|
|
25
|
+
end
|
|
16
26
|
end
|
|
17
27
|
end
|