Skip to content

Commit b85f6f5

Browse files
committed
[#71413] Upstream changes to BorderBox::CollapsibleHeader
https://community.openproject.org/work_packages/71413
1 parent 09f6ac7 commit b85f6f5

File tree

7 files changed

+107
-74
lines changed

7 files changed

+107
-74
lines changed
Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,17 @@
11
<%= render(Primer::BaseComponent.new(**@system_arguments)) do %>
2-
<%= render(Primer::OpenProject::FlexLayout.new(
3-
data: {
4-
target: "collapsible-header.triggerElement",
5-
action: "click:collapsible-header#toggle keydown:collapsible-header#toggleViaKeyboard"
6-
},
7-
tabindex: 0,
8-
role: "button",
9-
aria: {
10-
expanded: !@collapsed,
11-
},
12-
classes: "CollapsibleHeader--triggerArea"
13-
)) do |flex| %>
14-
<%= flex.with_row do %>
2+
<%= render(Primer::BaseComponent.new(**@trigger_area_arguments)) do %>
3+
<%= render(Primer::BaseComponent.new(tag: :div, classes: "CollapsibleHeader-title-line")) do %>
154
<%= title %>
165
<% if count? %>
176
<%= count %>
187
<% end %>
19-
<%= render(Primer::Beta::Octicon.new(icon: "chevron-up", hidden: @collapsed, data: { target: "collapsible-header.arrowUp" })) %>
20-
<%= render(Primer::Beta::Octicon.new(icon: "chevron-down", hidden: !@collapsed, data: { target: "collapsible-header.arrowDown" })) %>
21-
<% end %>
22-
<%= flex.with_row do %>
23-
<% if description? %>
24-
<%= description %>
8+
<%= render(Primer::BaseComponent.new(tag: :div, classes: "CollapsibleHeader-button--toggle")) do %>
9+
<%= render(Primer::Beta::Octicon.new(icon: "chevron-up", hidden: @collapsed, data: { target: "collapsible-header.arrowUp" })) %>
10+
<%= render(Primer::Beta::Octicon.new(icon: "chevron-down", hidden: !@collapsed, data: { target: "collapsible-header.arrowDown" })) %>
2511
<% end %>
2612
<% end %>
13+
<% if description? %>
14+
<%= description %>
15+
<% end %>
2716
<% end %>
2817
<% end %>
Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,59 @@
11
/* CSS for BorderBox::CollapsibleHeader */
22

33
.CollapsibleHeader {
4-
cursor: pointer;
5-
display: flex;
6-
align-items: center;
4+
display: block;
5+
container-name: collapsible-header-container;
6+
container-type: inline-size;
77
}
88

99
.Box:has(.CollapsibleHeader--collapsed) {
10-
border-bottom-left-radius: 0;
11-
border-bottom-right-radius: 0;
12-
border-bottom-width: var(--borderWidth-thicker);
13-
14-
& .Box-row,
15-
& .Box-body,
16-
& .Box-footer {
17-
display: none;
18-
}
10+
border-bottom-left-radius: 0;
11+
border-bottom-right-radius: 0;
12+
border-bottom-width: var(--borderWidth-thicker);
13+
14+
& .Box-row,
15+
& .Box-body,
16+
& .Box-footer {
17+
display: none;
18+
}
19+
}
20+
21+
.CollapsibleHeader-triggerArea {
22+
display: flex;
23+
flex-wrap: wrap;
24+
align-items: center;
25+
column-gap: var(--stack-gap-normal);
26+
row-gap: var(--base-size-4);
27+
flex: 1;
28+
}
29+
30+
@container collapsible-header-container (width < 544px) {
31+
.CollapsibleHeader-triggerArea {
32+
flex-direction: column;
33+
align-items: flex-start;
34+
}
35+
}
36+
37+
.CollapsibleHeader--two-line {
38+
.CollapsibleHeader-triggerArea {
39+
flex-direction: column;
40+
align-items: flex-start;
41+
}
42+
43+
&[data-collapsed] .CollapsibleHeader-description {
44+
display: none;
45+
}
46+
}
47+
48+
.CollapsibleHeader-title-line {
49+
display: flex;
50+
align-items: center;
51+
gap: var(--stack-gap-condensed);
52+
flex: 1;
53+
min-width: fit-content;
1954
}
2055

21-
.CollapsibleHeader--triggerArea {
22-
width: 100%;
56+
.CollapsibleHeader-description {
57+
display: inline;
58+
white-space: nowrap;
2359
}

app/components/primer/open_project/border_box/collapsible_header.rb

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ class CollapsibleHeader < Primer::Component
1212
#
1313
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
1414
renders_one :title, lambda { |**system_arguments, &block|
15-
system_arguments[:mr] ||= 2
15+
system_arguments[:classes] = class_names(
16+
system_arguments[:classes],
17+
"CollapsibleHeader-title",
18+
"Box-title"
19+
)
1620

1721
Primer::Beta::Text.new(**system_arguments, &block)
1822
}
@@ -23,6 +27,10 @@ class CollapsibleHeader < Primer::Component
2327
renders_one :count, lambda { |**system_arguments|
2428
system_arguments[:mr] ||= 2
2529
system_arguments[:scheme] ||= :primary
30+
system_arguments[:classes] = class_names(
31+
system_arguments[:classes],
32+
"CollapsibleHeader-count"
33+
)
2634

2735
Primer::Beta::Counter.new(**system_arguments)
2836
}
@@ -33,32 +41,35 @@ class CollapsibleHeader < Primer::Component
3341
renders_one :description, lambda { |**system_arguments, &block|
3442
system_arguments[:color] ||= :subtle
3543
system_arguments[:hidden] = @collapsed
36-
37-
system_arguments[:data] = merge_data(
38-
system_arguments, {
39-
data: {
40-
targets: "collapsible-header.collapsibleElements"
41-
}
42-
}
44+
system_arguments[:classes] = class_names(
45+
system_arguments[:classes],
46+
"CollapsibleHeader-description"
4347
)
4448

45-
Primer::Beta::Text.new(**system_arguments, &block)
49+
Primer::Beta::Text.new(**system_arguments)
4650
}
4751

48-
# @param id [String] The unique ID of the collapsible header.
52+
# @param box [Primer::Beta::BorderBox] Deprecated. Previously used to reference the parent BorderBox.
4953
# @param collapsed [Boolean] Whether the header is collapsed on initial render.
54+
# @param collapsible_id [String] The id of the element that will be collapsed.
55+
# @param toggle_label [String] The aria label for the toggle control.
56+
# @param two_line [Boolean] Whether the header always uses a two-line layout.
5057
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
51-
def initialize(id: self.class.generate_id, collapsed: false, box:, **system_arguments)
58+
def initialize(box: nil, collapsed: false, collapsible_id: nil, toggle_label: nil, two_line: true, **system_arguments)
59+
::Primer::ViewComponents.deprecation.warn("The `box:` param is deprecated and a no-op. It will be removed in a future version.") unless box.nil? && Rails.env.production?
5260
@collapsed = collapsed
53-
@box = box
54-
@system_arguments = system_arguments
55-
@system_arguments[:id] = id
56-
@system_arguments[:tag] = "collapsible-header"
61+
@collapsible_id = collapsible_id
62+
@toggle_label = toggle_label
63+
64+
@system_arguments = deny_tag_argument(**system_arguments)
65+
@system_arguments[:tag] = :"collapsible-header"
5766
@system_arguments[:classes] = class_names(
5867
system_arguments[:classes],
5968
"CollapsibleHeader",
60-
"CollapsibleHeader--collapsed" => @collapsed
69+
"CollapsibleHeader--collapsed" => @collapsed,
70+
"CollapsibleHeader--two-line" => two_line
6171
)
72+
6273
if @collapsed
6374
@system_arguments[:data] = merge_data(
6475
@system_arguments, {
@@ -69,6 +80,19 @@ def initialize(id: self.class.generate_id, collapsed: false, box:, **system_argu
6980
)
7081
end
7182

83+
@trigger_area_arguments = { tag: :div }
84+
@trigger_area_arguments[:role] = "button"
85+
@trigger_area_arguments[:tabindex] = 0
86+
@trigger_area_arguments[:classes] = "CollapsibleHeader-triggerArea"
87+
@trigger_area_arguments[:aria] = {
88+
label: @toggle_label,
89+
controls: @collapsible_id,
90+
expanded: !@collapsed
91+
}
92+
@trigger_area_arguments[:data] = {
93+
target: "collapsible-header.triggerElement",
94+
action: "click:collapsible-header#toggle keydown:collapsible-header#toggleViaKeyboard"
95+
}
7296
end
7397

7498
private
@@ -79,7 +103,6 @@ def before_render
79103

80104
def render?
81105
raise ArgumentError, "Title must be present" unless title?
82-
raise ArgumentError, "This component must be called inside the header of a `Primer::Beta::BorderBox`" unless @box.present? && @box.is_a?(Primer::Beta::BorderBox)
83106

84107
true
85108
end

previews/primer/open_project/border_box/collapsible_header_preview.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@ class CollapsibleHeaderPreview < ViewComponent::Preview
1212
# @param title [String]
1313
# @param description [String]
1414
# @param collapsed toggle
15+
# @param two_line toggle
1516
# @param count [Integer]
1617
def playground(
1718
title: "Backlog",
1819
description: "This backlog is unique to this one-time meeting. You can drag items in and out to add or remove them from the meeting agenda.",
1920
count: 42,
20-
collapsed: false
21+
collapsed: false,
22+
two_line: true
2123
)
2224
render_with_template(locals: {
2325
title: title,
2426
description: description,
2527
count: count,
26-
collapsed: collapsed
28+
collapsed: collapsed,
29+
two_line: two_line
2730
})
2831
end
2932

previews/primer/open_project/border_box/collapsible_header_preview/playground.html.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<%= render(Primer::Beta::BorderBox.new) do |component| %>
22
<% component.with_header do %>
3-
<%= render(Primer::OpenProject::BorderBox::CollapsibleHeader.new(box: component,
4-
collapsed: collapsed)) do |header| %>
3+
<%= render(Primer::OpenProject::BorderBox::CollapsibleHeader.new(collapsed: collapsed,
4+
two_line: two_line)) do |header| %>
55
<% header.with_title { title } %>
66
<% header.with_count(count: count) %>
77
<% header.with_description { description } %>

test/components/component_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class PrimerComponentTest < Minitest::Test
1313
component.with_collapsible_content { "Collapse me!" }
1414
}],
1515
[Primer::OpenProject::Fieldset, { legend_text: "My legend" }, proc { "Content" }],
16-
[Primer::OpenProject::BorderBox::CollapsibleHeader, { box: Primer::Beta::BorderBox.new }, proc { |component|
16+
[Primer::OpenProject::BorderBox::CollapsibleHeader, proc { |component|
1717
component.with_title { "Hello world" }
1818
}],
1919
[Primer::OpenProject::Heading, { tag: :h2 }],

test/components/primer/open_project/border_box/collapsible_header_test.rb

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,9 @@ def test_renders_default
1313
assert_selector("svg.octicon.octicon-chevron-down", visible: false)
1414
end
1515

16-
def test_does_not_render_without_box
17-
err = assert_raises ArgumentError do
18-
render_inline(Primer::OpenProject::BorderBox::CollapsibleHeader.new)
19-
end
20-
21-
assert_equal "missing keyword: :box", err.message
22-
end
23-
24-
def test_does_not_render_without_valid_box
25-
err = assert_raises ArgumentError do
26-
render_inline(Primer::OpenProject::BorderBox::CollapsibleHeader.new(box: "Some component")) do |header|
27-
header.with_title { "Test title" }
28-
end
29-
end
30-
31-
assert_equal "This component must be called inside the header of a `Primer::Beta::BorderBox`", err.message
32-
end
33-
3416
def test_does_not_render_with_empty_title
3517
err = assert_raises ArgumentError do
36-
render_inline(Primer::OpenProject::BorderBox::CollapsibleHeader.new(box: "Some component"))
18+
render_inline(Primer::OpenProject::BorderBox::CollapsibleHeader.new)
3719
end
3820

3921
assert_equal "Title must be present", err.message

0 commit comments

Comments
 (0)