Skip to content
代码片段 群组 项目
未验证 提交 33f495fc 编辑于 作者: Mark Florian's avatar Mark Florian
浏览文件

Add link_button_to helper

This provides an easier migration path for links that look like buttons
than using `Pajamas::ButtonComponent` itself. This is because the method
signature is much more similar to `link_to` than
`Pajamas::ButtonComponent`.

It's also slightly less verbose, which seems reasonable for such
a common use case.
上级 2e57b4fb
No related branches found
No related tags found
无相关合并请求
......@@ -464,6 +464,73 @@ def gitlab_ui_form_with(**args, &block)
form_with(**args.merge({ builder: ::Gitlab::FormBuilders::GitlabUiFormBuilder }), &block)
end
# Creates a link that looks like a button.
#
# It renders a Pajamas::ButtonComponent.
#
# It has the same API as `link_to`, but with some additional options
# specific to button rendering.
#
# Examples:
# # Default button
# link_button_to _('Foo'), some_path
#
# # Default button using a block
# link_button_to some_path do
# _('Foo')
# end
#
# # Confirm variant
# link_button_to _('Foo'), some_path, variant: :confirm
#
# # With icon
# link_button_to _('Foo'), some_path, icon: 'pencil'
#
# # Icon-only
# # NOTE: The content must be `nil` in order to correctly render. Use aria-label
# # to ensure the link is accessible.
# link_button_to nil, some_path, icon: 'pencil', 'aria-label': _('Foo')
#
# # Small button
# link_button_to _('Foo'), some_path, size: :small
#
# # Secondary category danger button
# link_button_to _('Foo'), some_path, variant: :danger, category: :secondary
#
# For accessibility, ensure that icon-only links have aria-label set.
def link_button_to(name = nil, options = nil, html_options = nil, &block)
if block
html_options = options
options = name
name = block
end
html_options ||= {}
# Ignore args that don't make sense for links, like disabled, loading, etc.
options_for_button = %i[
category
variant
size
block
selected
icon
target
method
]
args = html_options.slice(*options_for_button)
html_options = html_options.except(*options_for_button)
if block
render Pajamas::ButtonComponent.new(href: options, **args, button_options: html_options), &block
else
render Pajamas::ButtonComponent.new(href: options, **args, button_options: html_options) do
name
end
end
end
private
def browser_id
......
......@@ -619,6 +619,125 @@ def stub_controller_method(method_name, value)
end
end
describe '#link_button_to', feature_category: :design_system do
let(:content) { 'Button content' }
let(:options) { '#' }
let(:html_options) { {} }
RSpec.shared_examples 'basic behavior' do
it 'renders a basic link button' do
expect(subject.name).to eq('a')
expect(subject.classes).to include(*%w[gl-button btn btn-md btn-default])
expect(subject.attr('href')).to eq(options)
expect(subject.content.strip).to eq(content)
end
describe 'variant option' do
let(:html_options) { { variant: :danger } }
it 'renders the variant class' do
expect(subject.classes).to include('btn-danger')
end
end
describe 'category option' do
let(:html_options) { { category: :tertiary } }
it 'renders the category class' do
expect(subject.classes).to include('btn-default-tertiary')
end
end
describe 'size option' do
let(:html_options) { { size: :small } }
it 'renders the small class' do
expect(subject.classes).to include('btn-sm')
end
end
describe 'block option' do
let(:html_options) { { block: true } }
it 'renders the block class' do
expect(subject.classes).to include('btn-block')
end
end
describe 'selected option' do
let(:html_options) { { selected: true } }
it 'renders the selected class' do
expect(subject.classes).to include('selected')
end
end
describe 'target option' do
let(:html_options) { { target: '_blank' } }
it 'renders the target attribute' do
expect(subject.attr('target')).to eq('_blank')
end
end
describe 'method option' do
let(:html_options) { { method: :post } }
it 'renders the data-method attribute' do
expect(subject.attr('data-method')).to eq('post')
end
end
describe 'icon option' do
let(:html_options) { { icon: 'remove' } }
it 'renders the icon' do
icon = subject.at_css('svg.gl-icon')
expect(icon.attr('data-testid')).to eq('remove-icon')
end
end
describe 'icon only' do
let(:content) { nil }
let(:html_options) { { icon: 'remove' } }
it 'renders the icon-only class' do
expect(subject.classes).to include('btn-icon')
end
end
describe 'arbitrary html options' do
let(:content) { nil }
let(:html_options) { { data: { foo: true }, aria: { labelledby: 'foo' } } }
it 'renders the attributes' do
expect(subject.attr('data-foo')).to eq('true')
expect(subject.attr('aria-labelledby')).to eq('foo')
end
end
end
describe 'without block' do
subject do
tag = helper.link_button_to content, options, **html_options
Nokogiri::HTML.fragment(tag).first_element_child
end
include_examples 'basic behavior'
end
describe 'with block' do
subject do
tag = helper.link_button_to options, **html_options do
content
end
Nokogiri::HTML.fragment(tag).first_element_child
end
include_examples 'basic behavior'
end
end
describe '#page_class' do
subject(:page_class) do
helper.page_class.flatten
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册