From 2fa74ffb9619bced6a949cd4ca3f5df40cc8731b Mon Sep 17 00:00:00 2001 From: Chad Lavimoniere Date: Fri, 24 Jan 2025 10:30:11 -0500 Subject: [PATCH] Enable specifying a semantic element for the CRUD component container Currently, the CRUD component renders a `
` at its root. This MR leaves that default in place, but adds a prop to the Vue version and an option to the ViewComponent version that allows the dev to specify a different semantic element for the root of the component. This enables us to avoid some situations where using a `
` would be semantically inappropriate. Changelog: changed --- .../vue_shared/components/crud_component.vue | 10 ++++++++-- app/components/layouts/crud_component.haml | 2 +- app/components/layouts/crud_component.rb | 8 ++++++-- spec/components/layouts/crud_component_spec.rb | 7 +++++++ .../vue_shared/components/crud_component_spec.js | 5 +++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/vue_shared/components/crud_component.vue b/app/assets/javascripts/vue_shared/components/crud_component.vue index 00e9015e87f70f..5c7d899eb64773 100644 --- a/app/assets/javascripts/vue_shared/components/crud_component.vue +++ b/app/assets/javascripts/vue_shared/components/crud_component.vue @@ -53,6 +53,11 @@ export default { required: false, default: false, }, + containerTag: { + type: String, + required: false, + default: 'section', + }, isLoading: { type: Boolean, required: false, @@ -164,7 +169,8 @@ export default { diff --git a/app/components/layouts/crud_component.haml b/app/components/layouts/crud_component.haml index d7ac74ac8c826e..71321e90ea5282 100644 --- a/app/components/layouts/crud_component.haml +++ b/app/components/layouts/crud_component.haml @@ -1,4 +1,4 @@ -%section.crud.gl-bg-subtle.gl-border.gl-border-section.gl-rounded-base{ options_attrs, id: id } += content_tag @container_tag, **options_attrs, id: id do %header.crud-header.gl-flex.gl-flex-wrap.gl-justify-between.gl-gap-x-5.gl-gap-y-2.gl-px-5.gl-py-4.gl-bg-section.gl-border-b.gl-border-section.gl-rounded-t-base.gl-relative{ class: ('gl-pr-10' if @is_collapsible) } .gl-flex.gl-flex-col.gl-self-center %h2.gl-text-base.gl-font-bold.gl-leading-normal.gl-inline-flex.gl-gap-3.gl-m-0{ data: { testid: 'crud-title' } } diff --git a/app/components/layouts/crud_component.rb b/app/components/layouts/crud_component.rb index 3a847cedd75783..99576d7e0dbc9e 100644 --- a/app/components/layouts/crud_component.rb +++ b/app/components/layouts/crud_component.rb @@ -15,11 +15,12 @@ class CrudComponent < ViewComponent::Base # @param [Hash] toggle_options # @param [Hash] footer_options # @param [Boolean] is_collapsible + # @param [String] container_tag def initialize( title, description: nil, count: nil, icon: nil, icon_class: nil, toggle_text: nil, options: {}, count_options: {}, body_options: {}, form_options: {}, toggle_options: {}, footer_options: {}, - is_collapsible: false + is_collapsible: false, container_tag: 'section' ) @title = title @description = description @@ -34,6 +35,7 @@ def initialize( @toggle_options = toggle_options @footer_options = footer_options @is_collapsible = is_collapsible + @container_tag = container_tag end renders_one :description @@ -48,11 +50,13 @@ def id end def options_attrs + default_testid = 'haml-crud' default_classes = [ + 'crud', 'gl-bg-subtle', 'gl-border', 'gl-border-section', 'gl-rounded-base', ('js-toggle-container' if @toggle_text), ('js-crud-collapsible-section' if @is_collapsible) ] - @options.merge(default_attrs(@options, nil, default_classes)) + @options.merge(default_attrs(@options, default_testid, default_classes)) end def body_options_attrs diff --git a/spec/components/layouts/crud_component_spec.rb b/spec/components/layouts/crud_component_spec.rb index 5c4cc1ff49d3eb..577e78637b3d73 100644 --- a/spec/components/layouts/crud_component_spec.rb +++ b/spec/components/layouts/crud_component_spec.rb @@ -15,6 +15,13 @@ let(:pagination) { 'Pagination' } let(:component_title) { described_class.new(title) } + describe 'container_tag' do + it 'renders the element specified by container_tag option' do + render_inline described_class.new(title, container_tag: :div) + expect(page).to have_selector('div[data-testid="haml-crud"]') + end + end + describe 'slots' do it 'renders title' do render_inline component_title diff --git a/spec/frontend/vue_shared/components/crud_component_spec.js b/spec/frontend/vue_shared/components/crud_component_spec.js index 01bc9914852aab..f88820663064e3 100644 --- a/spec/frontend/vue_shared/components/crud_component_spec.js +++ b/spec/frontend/vue_shared/components/crud_component_spec.js @@ -46,6 +46,11 @@ describe('CRUD Component', () => { expect(findTitle().text()).toBe('CRUD Component title'); }); + it('renders the element specified by the containerTag prop', () => { + createComponent({ containerTag: 'span' }); + expect(wrapper.element.tagName).toBe('SPAN'); + }); + it('renders `title` slot', () => { createComponent({}, { title: '

Title slot

' }); -- GitLab