Skip to content

Commit ed2cd0c

Browse files
committed
Use Primer patterns in FilterFormComponent
Uses `ConditionalWrapper` to eliminate template duplication in the `wrap_with_controller` branch, and `merge_data` from `Primer::AttributesHelper` for Stimulus data attributes.
1 parent a5ee2b5 commit ed2cd0c

5 files changed

Lines changed: 73 additions & 40 deletions

File tree

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
<% if @wrap_with_controller %>
2-
<%= tag.div(class: "op-filters-form -expanded", data: controller_data_attributes) do %>
3-
<%= hidden_filters_input if @hidden_input_name %>
4-
<%= render(form_list) %>
5-
<% end %>
6-
<% else %>
1+
<%= render(
2+
Primer::ConditionalWrapper.new(
3+
condition: @wrap_with_controller,
4+
**@wrapper_arguments
5+
)
6+
) do %>
77
<%= hidden_filters_input if @hidden_input_name %>
88
<%= render(form_list) %>
99
<% end %>

app/components/filters/filter_form_component.rb

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,41 @@
7474
# in a Primer dialog or another container that clips overflow, so the dropdown
7575
# portal renders outside that container instead of being clipped.
7676
class Filters::FilterFormComponent < ApplicationComponent
77+
include Primer::AttributesHelper
78+
include Primer::FetchOrFallbackHelper
79+
7780
OUTPUT_FORMATS = %i[params json].freeze
7881

7982
def initialize(builder:, query:,
8083
allowed_filters: nil,
8184
wrap_with_controller: false,
8285
hidden_input_name: nil,
8386
output_format: nil,
84-
autocomplete_append_to: nil)
87+
autocomplete_append_to: nil,
88+
**wrapper_arguments)
8589
super()
8690
@builder = builder
8791
@query = query
8892
@allowed_filters = allowed_filters || query.available_advanced_filters
8993
@wrap_with_controller = wrap_with_controller
9094
@hidden_input_name = hidden_input_name
91-
@output_format = validate_output_format(output_format)
95+
@output_format = fetch_or_fallback(OUTPUT_FORMATS, output_format.to_sym) if output_format
9296
@autocomplete_append_to = autocomplete_append_to
97+
@wrapper_arguments = wrapper_arguments
98+
@wrapper_arguments[:tag] ||= :div
99+
@wrapper_arguments[:classes] = class_names(
100+
"op-filters-form -expanded",
101+
@wrapper_arguments[:classes]
102+
)
103+
@wrapper_arguments[:data] = merge_data(
104+
@wrapper_arguments,
105+
{
106+
data: {
107+
controller: "filter--filters-form",
108+
filter__filters_form_output_format_value: @output_format&.to_s
109+
}
110+
}
111+
)
93112
end
94113

95114
private
@@ -100,23 +119,6 @@ def form_list
100119
Primer::Forms::FormList.new(*sub_forms)
101120
end
102121

103-
def controller_data_attributes
104-
attrs = { controller: "filter--filters-form" }
105-
attrs["filter--filters-form-output-format-value"] = @output_format.to_s if @output_format
106-
attrs
107-
end
108-
109-
def validate_output_format(format)
110-
return nil if format.nil?
111-
112-
sym = format.to_sym
113-
unless OUTPUT_FORMATS.include?(sym)
114-
raise ArgumentError,
115-
"Unknown output_format #{format.inspect}; expected one of #{OUTPUT_FORMATS.inspect}"
116-
end
117-
sym
118-
end
119-
120122
def hidden_filters_input
121123
hidden_field_tag(
122124
@hidden_input_name,

lookbook/docs/patterns/11-filter-forms.md.erb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,10 @@ The host server receives the canonical string in
9898

9999
### Combining with non-filter inputs
100100

101-
`FilterFormComponent` composes with other forms via
102-
`Primer::Forms::FormList`. All children share the same builder and
103-
therefore submit through the same `<form>`.
101+
`FilterFormComponent` is rendered next to normal Primer form objects, not
102+
inside `Primer::Forms::FormList`. Render any regular form objects through
103+
a `FormList`, then render `FilterFormComponent` with the same builder. All
104+
fields still submit through the same surrounding `<form>`.
104105

105106
<%= embed OpenProject::Filter::FilterFormPreview, :combined_with_other_inputs, panels: %i[preview source] %>
106107

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
<%# `Filters::FilterFormComponent` is a component — combine it with %>
2-
<%# other forms in a single `Primer::Forms::FormList` to share one builder %>
3-
<%# (and therefore one submission) with non-filter inputs. %>
1+
<%# `Filters::FilterFormComponent` is a ViewComponent that shares the %>
2+
<%# surrounding Primer form builder with other form objects. Render normal %>
3+
<%# Primer form objects through FormList, then render the filter component %>
4+
<%# next to that list with the same builder. %>
45
<%
56
note_form = Class.new(ApplicationForm) do
67
form do |f|
@@ -9,17 +10,13 @@
910
end
1011
%>
1112
<%= primer_form_with(url: "/foo", method: :post) do |f| %>
12-
<%=
13-
render(
14-
Primer::Forms::FormList.new(
15-
note_form.new(f),
13+
<%= render(Primer::Forms::FormList.new(note_form.new(f))) %>
14+
<%= render(
1615
Filters::FilterFormComponent.new(
1716
builder: f,
1817
query: query,
1918
wrap_with_controller: true,
2019
hidden_input_name: "filters"
2120
)
22-
)
23-
)
24-
%>
21+
) %>
2522
<% end %>

spec/components/filters/filter_form_component_spec.rb

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ def render_form(form_options = options)
140140
it "omits the data attribute by default" do
141141
render_form(query:, wrap_with_controller: true)
142142

143-
# The controller wrapper exists, but without the output-format attribute.
144143
expect(page).to have_element "data-controller": "filter--filters-form" do |wrapper|
145144
expect(wrapper["data-filter--filters-form-output-format-value"]).to be_nil
146145
end
@@ -149,7 +148,41 @@ def render_form(form_options = options)
149148
it "raises on unknown values" do
150149
expect do
151150
described_class.new(builder: nil, query:, output_format: :bogus)
152-
end.to raise_error(ArgumentError, /Unknown output_format/)
151+
end.to raise_error(Primer::FetchOrFallbackHelper::InvalidValueError, /Expected one of/)
152+
end
153+
end
154+
155+
describe "wrapper system arguments" do
156+
it "forwards standard system arguments to the controller wrapper" do
157+
render_form(
158+
query:,
159+
wrap_with_controller: true,
160+
id: "custom-filter-wrapper",
161+
aria: { label: "Filters" },
162+
data: { test_selector: "filters-wrapper" }
163+
)
164+
165+
expect(page).to have_element :div,
166+
id: "custom-filter-wrapper",
167+
"aria-label": "Filters",
168+
"data-test-selector": "filters-wrapper"
169+
end
170+
171+
it "merges caller classes and data with the required wrapper data" do
172+
render_form(
173+
query:,
174+
wrap_with_controller: true,
175+
classes: "custom-class",
176+
data: {
177+
controller: "custom-controller",
178+
action: "keydown->custom#close"
179+
}
180+
)
181+
182+
expect(page).to have_element :div,
183+
class: %w[op-filters-form -expanded custom-class],
184+
"data-controller": "filter--filters-form",
185+
"data-action": "keydown->custom#close"
153186
end
154187
end
155188

0 commit comments

Comments
 (0)