Skip to content

Commit

Permalink
Add with_outlets method, and allow outlets to be used when component …
Browse files Browse the repository at this point in the history
…has no id, and when outlet is specified as a symbol, and update tests
  • Loading branch information
stevegeek committed Feb 25, 2024
1 parent 5bede01 commit d303431
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 26 deletions.
44 changes: 31 additions & 13 deletions lib/vident/root_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ def target_data_attribute(name)
end

def build_outlet_selector(outlet_selector)
"##{@id} [data-controller~=#{outlet_selector}]"
prefix = @id ? "##{@id} " : ""
"#{prefix}[data-controller~=#{outlet_selector}]"
end

def outlet(css_selector: nil)
Expand Down Expand Up @@ -108,6 +109,13 @@ def with_actions(*actions_to_set)
end
alias_method :with_action, :with_actions

# Return the HTML `data-` attribute for the given outlets
def with_outlets(*outlets)
attrs = build_outlet_data_attributes(outlets)
attrs.map { |dt, n| "data-#{dt}=\"#{n}\"" }.join(" ").html_safe
end
alias_method :with_outlet, :with_outlets

private

# An implicit Stimulus controller name is built from the implicit controller path
Expand Down Expand Up @@ -154,19 +162,29 @@ def tag_data_attributes

def outlet_list
return {} unless @outlets&.size&.positive?
build_outlet_data_attributes(@outlets)
end

def parse_outlet(outlet_config)
if outlet_config.is_a?(String)
[outlet_config, build_outlet_selector(outlet_config)]
elsif outlet_config.is_a?(Symbol)
outlet_config = outlet_config.to_s.tr("_", "-")
[outlet_config, build_outlet_selector(outlet_config)]
elsif outlet_config.is_a?(Array)
outlet_config[..1]
elsif outlet_config.respond_to?(:stimulus_identifier) # Is a Component
[outlet_config.stimulus_identifier, build_outlet_selector(outlet_config.stimulus_identifier)]
elsif outlet_config.send(:implied_controller_name) # Is a RootComponent ?
[outlet_config.send(:implied_controller_name), build_outlet_selector(outlet_config.send(:implied_controller_name))]
else
raise ArgumentError, "Invalid outlet config: #{outlet_config}"
end
end

@outlets.each_with_object({}) do |outlet_config, obj|
identifier, css_selector = if outlet_config.is_a?(String)
[outlet_config, build_outlet_selector(outlet_config)]
elsif outlet_config.is_a?(Array)
outlet_config[..1]
elsif outlet_config.respond_to?(:stimulus_identifier) # Is a Component
[outlet_config.stimulus_identifier, build_outlet_selector(outlet_config.stimulus_identifier)]
elsif outlet_config.send(:implied_controller_name) # Is a RootComponent ?
[outlet_config.send(:implied_controller_name), build_outlet_selector(outlet_config.send(:implied_controller_name))]
else
raise ArgumentError, "Invalid outlet config: #{outlet_config}"
end
def build_outlet_data_attributes(outlets)
outlets.each_with_object({}) do |outlet_config, obj|
identifier, css_selector = parse_outlet(outlet_config)
obj[:"#{implied_controller_name}-#{identifier}-outlet"] = css_selector
end
end
Expand Down
38 changes: 25 additions & 13 deletions test/vident/root_component_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
module Vident
class RootComponentTest < Minitest::Test
def setup
component = Class.new do
@component = Class.new do
include Vident::RootComponent

def get_all_data_attrs
tag_data_attributes
end
end
@root_component = component.new(controllers: ["foo/my_controller"])
@root_component = @component.new(controllers: ["foo/my_controller"])
end

def test_action
Expand All @@ -26,8 +26,8 @@ def test_target
end

def test_named_classes
@root_component.instance_variable_set(:@named_classes, {my_class: "my-class"})
assert_equal "my-class", @root_component.named_classes(:my_class)
root = @component.new(controllers: ["foo/my_controller"], named_classes: {my_class: "my-class"})
assert_equal "my-class", root.named_classes(:my_class)
end

def test_action_data_attribute
Expand All @@ -51,27 +51,39 @@ def test_with_actions
assert_equal "data-action='foo--my-controller#myAction'", @root_component.with_actions(:my_action)
end

def test_outlet_selector_when_no_id
root_component = @component.new(controllers: ["foo/my_controller"], id: "the-id")
assert_equal "data-foo--my-controller-my-outlet-outlet=\"#the-id [data-controller~=my-outlet]\"", root_component.with_outlets(:my_outlet)
end

def test_with_outlets_no_id
assert_equal "data-foo--my-controller-my-outlet-outlet=\"[data-controller~=my-outlet]\"", @root_component.with_outlets(:my_outlet)
end

def test_get_all_data_attrs
# Setup
@root_component.instance_variable_set(:@named_classes, {my_class: "my-class"})
@root_component.instance_variable_set(:@outlets, ["my-outlet", ["other-component", "#my_id"]])
@root_component.instance_variable_set(:@data_maps, [{my_key: "my-value"}])
@root_component.instance_variable_set(:@actions, [:my_action])
@root_component.instance_variable_set(:@targets, [:my_target])
root_component = @component.new(
id: "the-id",
controllers: ["foo/my_controller"],
named_classes: {my_class: "my-class"},
outlets: ["my-outlet", ["other-component", ".custom-selector"]],
data_maps: [{my_key: "my-value"}],
actions: [:my_action],
targets: [:my_target]
)

# Expected result
expected_result = {
controller: "foo--my-controller",
action: "foo--my-controller#myAction",
"foo--my-controller-target": "myTarget",
"foo--my-controller-my-outlet-outlet": "[data-controller~=my-outlet]",
"foo--my-controller-other-component-outlet": "#my_id",
"foo--my-controller-my-outlet-outlet": "#the-id [data-controller~=my-outlet]",
"foo--my-controller-other-component-outlet": ".custom-selector",
"foo--my-controller-my-class-class": "my-class",
"foo--my-controller-my_key": "my-value"
}

# Test
assert_equal expected_result, @root_component.get_all_data_attrs
assert_equal expected_result, root_component.get_all_data_attrs
end
end
end

0 comments on commit d303431

Please sign in to comment.