Skip to content

Add #with_outlets method, and allow outlets to be used when component … #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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