@@ -20,10 +20,12 @@ class PageHeader < Primer::Component
2020 "triangle-left"
2121 ] . freeze
2222
23+ DEFAULT_ACTION_SCHEME = :default
24+ MORE_MENU_DISPLAY = [ :flex , :none ] . freeze
25+
2326 DEFAULT_LEADING_ACTION_DISPLAY = [ :none , :flex ] . freeze
2427 DEFAULT_BREADCRUMBS_DISPLAY = [ :none , :flex ] . freeze
2528 DEFAULT_PARENT_LINK_DISPLAY = [ :block , :none ] . freeze
26- DEFAULT_CONTEXT_BAR_ACTIONS_DISPLAY = [ :flex , :none ] . freeze
2729
2830 status :open_project
2931
@@ -54,24 +56,50 @@ class PageHeader < Primer::Component
5456 # Actions
5557 #
5658 # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
57- renders_many :actions , lambda { |**system_arguments |
58- deny_tag_argument ( **system_arguments )
59- system_arguments [ :tag ] = :div
60- system_arguments [ :ml ] ||= 2
59+ renders_many :actions , types : {
60+ icon_button : lambda { |icon :, mobile_icon :, label :, scheme : DEFAULT_ACTION_SCHEME , **system_arguments |
61+ deny_tag_argument ( **system_arguments )
62+ system_arguments = set_action_arguments ( system_arguments , scheme : scheme )
63+ add_option_to_mobile_menu ( system_arguments , mobile_icon , label , scheme )
6164
62- Primer ::BaseComponent . new ( **system_arguments )
63- }
65+ Primer ::Beta ::IconButton . new ( icon : icon , "aria-label" : label , **system_arguments )
66+ } ,
67+ button : lambda { |mobile_icon :, mobile_label :, scheme : DEFAULT_ACTION_SCHEME , **system_arguments |
68+ deny_tag_argument ( **system_arguments )
69+ system_arguments = set_action_arguments ( system_arguments , scheme : scheme )
70+ add_option_to_mobile_menu ( system_arguments , mobile_icon , mobile_label , scheme )
6471
65- # Context Bar Actions
66- # By default shown on narrow screens. Can be overridden with system_argument: display
67- #
68- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
69- renders_many :context_bar_actions , lambda { |**system_arguments |
70- deny_tag_argument ( **system_arguments )
71- system_arguments [ :tag ] = :div
72- system_arguments [ :ml ] ||= 2
72+ Primer ::Beta ::Button . new ( **system_arguments )
73+ } ,
74+ link : lambda { |mobile_icon :, mobile_label :, scheme : DEFAULT_ACTION_SCHEME , **system_arguments |
75+ deny_tag_argument ( **system_arguments )
76+ system_arguments = set_action_arguments ( system_arguments , scheme : scheme )
77+ add_option_to_mobile_menu ( system_arguments , mobile_icon , mobile_label , scheme )
7378
74- Primer ::BaseComponent . new ( **system_arguments )
79+ Primer ::Beta ::Link . new ( **system_arguments )
80+ } ,
81+ # Should only be used rarely on a per-need basis
82+ text : lambda { |**system_arguments |
83+ system_arguments = set_action_arguments ( system_arguments )
84+
85+ system_arguments [ :color ] ||= :muted
86+
87+ # Enforce that texts are hidden on mobile
88+ system_arguments [ :display ] = [ :none , :flex ]
89+
90+ Primer ::Beta ::Text . new ( **system_arguments )
91+ } ,
92+ menu : {
93+ renders : lambda { |**system_arguments , &block |
94+ deny_tag_argument ( **system_arguments )
95+ system_arguments [ :menu_arguments ] = set_action_arguments ( system_arguments [ :menu_arguments ] )
96+
97+ # Add the options individually to the mobile menu in the template
98+ @desktop_menu_block = block
99+
100+ PageHeaderActionMenu . new ( **system_arguments )
101+ } ,
102+ } ,
75103 }
76104
77105 # Optional leading action prepend the title
@@ -93,21 +121,6 @@ class PageHeader < Primer::Component
93121 Primer ::Beta ::IconButton . new ( icon : icon , **system_arguments )
94122 }
95123
96- # Optional parent link in the context area
97- # By default shown on narrow screens. Can be overridden with system_argument: display
98- #
99- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
100- renders_one :parent_link , lambda { |icon : DEFAULT_BACK_BUTTON_ICON , **system_arguments , &block |
101- deny_tag_argument ( **system_arguments )
102- system_arguments [ :icon ] = fetch_or_fallback ( BACK_BUTTON_ICON_OPTIONS , icon , DEFAULT_BACK_BUTTON_ICON )
103- system_arguments [ :classes ] = class_names ( system_arguments [ :classes ] , "PageHeader-parentLink" )
104- system_arguments [ :display ] ||= DEFAULT_PARENT_LINK_DISPLAY
105-
106- render ( Primer ::Beta ::Link . new ( scheme : :primary , muted : true , **system_arguments ) ) do
107- render ( Primer ::Beta ::Octicon . new ( icon : "arrow-left" , "aria-label" : "aria_label" , mr : 2 ) ) + content_tag ( :span , &block )
108- end
109- }
110-
111124 # Optional breadcrumbs above the title row
112125 # By default shown on wider screens. Can be overridden with system_argument: display
113126 #
@@ -117,6 +130,25 @@ class PageHeader < Primer::Component
117130 system_arguments [ :classes ] = class_names ( system_arguments [ :classes ] , "PageHeader-breadcrumbs" )
118131 system_arguments [ :display ] ||= DEFAULT_BREADCRUMBS_DISPLAY
119132
133+ # show parent link if there is a parent for current page
134+ if items . length > 1
135+ link_arguments = { }
136+ parent_item = items [ items . length - 2 ]
137+ parsed_parent_item = anchor_tag_string? ( parent_item ) ? anchor_string_to_object ( parent_item ) : parent_item
138+
139+ link_arguments [ :icon ] = fetch_or_fallback ( BACK_BUTTON_ICON_OPTIONS , DEFAULT_BACK_BUTTON_ICON )
140+ link_arguments [ :href ] = parsed_parent_item [ :href ]
141+ link_arguments [ :classes ] = class_names ( link_arguments [ :classes ] , "PageHeader-parentLink" )
142+ link_arguments [ :display ] ||= DEFAULT_PARENT_LINK_DISPLAY
143+
144+ @parent_link = render ( Primer ::Beta ::Link . new ( scheme : :primary , muted : true , **link_arguments ) ) do
145+ render ( Primer ::Beta ::Octicon . new ( icon : "arrow-left" ,
146+ "aria-label" : I18n . t ( "button_back" ) ,
147+ mr : 2 )
148+ ) + content_tag ( :span , parsed_parent_item [ :text ] )
149+ end
150+ end
151+
120152 render ( Primer ::Beta ::Breadcrumbs . new ( **system_arguments ) ) do |breadcrumbs |
121153 items . each do |item |
122154 item = anchor_string_to_object ( item ) if anchor_tag_string? ( item )
@@ -130,23 +162,83 @@ class PageHeader < Primer::Component
130162 end
131163 }
132164
133- def initialize ( **system_arguments )
165+ # @param mobile_menu_label [String] The tooltip label of the mobile menu
166+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
167+ def initialize ( mobile_menu_label : I18n . t ( "label_more" ) , **system_arguments )
134168 @system_arguments = deny_tag_argument ( **system_arguments )
169+ @mobile_menu_label = mobile_menu_label
135170
136- @system_arguments [ :tag ] = :header
171+ @system_arguments [ :tag ] = :"page- header"
137172 @system_arguments [ :classes ] =
138173 class_names (
139174 @system_arguments [ :classes ] ,
140175 "PageHeader"
141176 )
177+
178+ @mobile_action_menu = Primer ::Alpha ::ActionMenu . new (
179+ display : MORE_MENU_DISPLAY ,
180+ anchor_align : :end
181+ )
142182 end
143183
144184 def render?
145- title?
185+ raise ArgumentError , "PageHeader needs a title and a breadcrumb. Please use the `with_title` and `with_breadcrumbs` slot" unless breadcrumbs? || Rails . env . production?
186+ title? && breadcrumbs?
187+ end
188+
189+ def before_render
190+ @system_arguments [ :classes ] = class_names (
191+ @system_arguments [ :classes ] ,
192+ "PageHeader--singleAction" : !render_mobile_menu?
193+ )
194+
195+ content
196+ end
197+
198+ def render_mobile_menu?
199+ actions . count > 1
146200 end
147201
148202 private
149203
204+ def set_action_arguments ( system_arguments , scheme : nil )
205+ system_arguments [ :ml ] ||= 2
206+ system_arguments [ :display ] = [ :none , :flex ]
207+ system_arguments [ :scheme ] = scheme unless scheme . nil?
208+ system_arguments [ :classes ] = class_names (
209+ system_arguments [ :classes ] ,
210+ "PageHeader-action" ,
211+ )
212+
213+ system_arguments [ :id ] ||= self . class . generate_id
214+ system_arguments
215+ end
216+
217+ def add_option_to_mobile_menu ( system_arguments , mobile_icon , mobile_label , scheme )
218+ unless mobile_icon . nil? || mobile_label . nil?
219+ # In action menus, only :default and :danger are allowed
220+ scheme = DEFAULT_ACTION_SCHEME unless scheme == :danger
221+
222+ with_menu_item ( id : system_arguments [ :id ] , label : mobile_label , scheme : scheme ) do |c |
223+ c . with_leading_visual_icon ( icon : mobile_icon )
224+ end
225+ end
226+ end
227+
228+ def with_menu_item ( id :, **system_arguments , &block )
229+ system_arguments = {
230+ **system_arguments ,
231+ "data-for" : id ,
232+ "data-action" : "click:page-header#menuItemClick"
233+ }
234+
235+ @mobile_action_menu . with_item (
236+ value : "" ,
237+ **system_arguments ,
238+ &block
239+ )
240+ end
241+
150242 # transform anchor tag strings to {href, text} objects
151243 # e.g "\u003ca href=\"/admin\"\u003eAdministration\u003c/a\u003e"
152244 def anchor_string_to_object ( html_string )
@@ -161,6 +253,30 @@ def anchor_string_to_object(html_string)
161253 def anchor_tag_string? ( item )
162254 item . is_a? ( String ) && item . start_with? ( "\u003c " )
163255 end
256+
257+ # A Helper class to create ActionMenus inside the PageHeader action slot
258+ class PageHeaderActionMenu < Primer ::Component
259+ # @param menu_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::ActionMenu) %>.
260+ # @param button_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::Button) %> or <%= link_to_component(Primer::Beta::IconButton) %>, depending on the value of the `icon:` argument.
261+ def initialize ( menu_arguments : { } , button_arguments : { } )
262+ @menu = Primer ::Alpha ::ActionMenu . new ( **menu_arguments )
263+ @button = @menu . with_show_button ( icon : "triangle-down" , **button_arguments )
264+ end
265+
266+ def render_in ( view_context , &block )
267+ super ( view_context ) do
268+ block . call ( @menu , @button )
269+ end
270+ end
271+
272+ def before_render
273+ content
274+ end
275+
276+ def call
277+ render ( @menu )
278+ end
279+ end
164280 end
165281 end
166282end
0 commit comments