Skip to content

Commit

Permalink
Merge pull request #382 from DFE-Digital/table-header-scopes
Browse files Browse the repository at this point in the history
Add scope support for table headers
  • Loading branch information
peteryates authored Jan 5, 2023
2 parents 1462528 + f68a2a5 commit dba59da
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 47 deletions.
7 changes: 0 additions & 7 deletions app/components/govuk_component/table_component.html.erb

This file was deleted.

4 changes: 4 additions & 0 deletions app/components/govuk_component/table_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ def initialize(id: nil, rows: nil, head: nil, caption: nil, first_cell_is_header
build(*(head ? [head, rows] : [rows[0], rows[1..]]), caption_text)
end

def call
tag.table(**html_attributes) { safe_join([caption, head, bodies]) }
end

private

def build(head_data, body_data, caption_text)
Expand Down

This file was deleted.

14 changes: 13 additions & 1 deletion app/components/govuk_component/table_component/body_component.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
class GovukComponent::TableComponent::BodyComponent < GovukComponent::Base
renders_many :rows, "GovukComponent::TableComponent::RowComponent"
renders_many :rows, ->(cell_data: nil, first_cell_is_header: false, classes: [], html_attributes: {}, &block) do
GovukComponent::TableComponent::RowComponent.from_body(
cell_data: cell_data,
first_cell_is_header: first_cell_is_header,
classes: classes,
html_attributes: html_attributes,
&block
)
end

def initialize(rows: nil, first_cell_is_header: false, classes: [], html_attributes: {})
super(classes: classes, html_attributes: html_attributes)

build_rows_from_row_data(rows, first_cell_is_header)
end

def call
tag.tbody(**html_attributes) { safe_join(rows) }
end

private

def build_rows_from_row_data(data, first_cell_is_header)
Expand Down
34 changes: 28 additions & 6 deletions app/components/govuk_component/table_component/cell_component.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
class GovukComponent::TableComponent::CellComponent < GovukComponent::Base
attr_reader :text, :header, :numeric, :width
attr_reader :text, :header, :numeric, :width, :scope, :parent

alias_method :numeric?, :numeric
alias_method :header?, :header

WIDTHS = {
"full" => "govuk-!-width-full",
Expand All @@ -12,11 +13,13 @@ class GovukComponent::TableComponent::CellComponent < GovukComponent::Base
"one-quarter" => "govuk-!-width-one-quarter",
}.freeze

def initialize(header: false, text: nil, numeric: false, width: nil, classes: [], html_attributes: {})
def initialize(scope: nil, header: false, numeric: false, text: nil, width: nil, parent: nil, classes: [], html_attributes: {})
@header = header
@text = text
@numeric = numeric
@width = width
@scope = scope
@parent = parent

super(classes: classes, html_attributes: html_attributes)
end
Expand All @@ -36,18 +39,37 @@ def cell_content
end

def cell_element
header ? :th : :td
header ? 'th' : 'td'
end

def default_attributes
{ class: default_classes }
{ class: default_classes, scope: determine_scope }
end

def determine_scope
conditions = { scope: scope, parent: parent, header: header, auto_table_scopes: config.enable_auto_table_scopes }

case conditions
in { scope: String }
scope
in { scope: false } | { header: false } | { auto_table_scopes: false }
nil
in { auto_table_scopes: true, parent: 'thead' }
'col'
in { auto_table_scopes: true, parent: 'tbody' }
'row'
else
Rails.logger.warning("No scope pattern matched")

nil
end
end

def default_classes
if header
class_names("govuk-table__header", "govuk-table__header--numeric" => numeric?, width_class => width?).split
class_names("govuk-table__header", "govuk-table__header--numeric" => numeric?, width_class => width?)
else
class_names("govuk-table__cell", "govuk-table__cell--numeric" => numeric?, width_class => width?).split
class_names("govuk-table__cell", "govuk-table__cell--numeric" => numeric?, width_class => width?)
end
end

Expand Down

This file was deleted.

14 changes: 13 additions & 1 deletion app/components/govuk_component/table_component/head_component.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
class GovukComponent::TableComponent::HeadComponent < GovukComponent::Base
renders_many :rows, "GovukComponent::TableComponent::RowComponent"
renders_many :rows, ->(cell_data: nil, header: true, classes: [], html_attributes: {}, &block) do
GovukComponent::TableComponent::RowComponent.from_head(
cell_data: cell_data,
header: header,
classes: classes,
html_attributes: html_attributes,
&block
)
end

attr_reader :row_data

Expand All @@ -9,6 +17,10 @@ def initialize(rows: nil, classes: [], html_attributes: {})
build_rows_from_row_data(rows)
end

def call
tag.thead(**html_attributes) { safe_join(rows) }
end

private

def build_rows_from_row_data(data)
Expand Down

This file was deleted.

39 changes: 35 additions & 4 deletions app/components/govuk_component/table_component/row_component.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,54 @@
class GovukComponent::TableComponent::RowComponent < GovukComponent::Base
renders_many :cells, "GovukComponent::TableComponent::CellComponent"
renders_many :cells, ->(scope: nil, header: false, text: nil, numeric: false, width: nil, classes: [], html_attributes: {}, &block) do
GovukComponent::TableComponent::CellComponent.new(
scope: scope,
header: header,
text: text,
numeric: numeric,
width: width,
parent: parent,
classes: classes,
html_attributes: html_attributes,
&block
)
end

attr_reader :header, :first_cell_is_header
attr_reader :header, :first_cell_is_header, :parent

def initialize(cell_data: nil, first_cell_is_header: false, header: false, classes: [], html_attributes: {})
def initialize(cell_data: nil, first_cell_is_header: false, header: false, parent: nil, classes: [], html_attributes: {})
@header = header
@first_cell_is_header = first_cell_is_header
@parent = parent

super(classes: classes, html_attributes: html_attributes)

build_cells_from_cell_data(cell_data)
end

def self.from_head(*args, **kwargs, &block)
new(*args, parent: 'thead', **kwargs, &block)
end

def self.from_body(*args, **kwargs, &block)
new(*args, parent: 'tbody', **kwargs, &block)
end

def call
tag.tr(**html_attributes) { safe_join(cells) }
end

private

def build_cells_from_cell_data(cell_data)
return if cell_data.blank?

cell_data.map.with_index { |cd, i| cell(header: cell_is_header?(i), text: cd) }
cell_data.each.with_index { |data, i| cell(text: data, **cell_attributes(i)) }
end

def cell_attributes(count)
cell_is_header?(count).then do |cell_is_header|
{ header: cell_is_header }
end
end

def cell_is_header?(count)
Expand Down
3 changes: 3 additions & 0 deletions guide/content/components/table.slim
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ p Use the table component to make information easier to compare and scan for
using the `head` argument. If nothing is set, the first row will be used for
headers.

The `first_cell_is_header` parameter can be used to change the first column
in the table body to header cells with `scope='row'`.

== render('/partials/example.*',
caption: "Table with resized columns",
code: table_with_resized_columns) do
Expand Down
12 changes: 6 additions & 6 deletions guide/lib/examples/table_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,19 @@ def table_with_header_column

def table_from_arrays
<<~TABLE
= govuk_table(rows: data, caption: "Pokémon species and types")
= govuk_table(rows: data, caption: "Pokémon species and types", first_cell_is_header: true)
TABLE
end

def table_data
<<~TABLE_DATA
{
data: [
["Name", "Primary type"],
["Weedle", "Bug"],
["Rattata", "Normal"],
["Raichu", "Electric"],
["Golduck", "Water"]
["Name" , "Primary type", "Catch rate", "Other types"],
["Weedle" , "Bug" , 255 , "Poison"],
["Rattata", "Normal" , 255 , "Dark"],
["Raichu" , "Electric" , 75 , "Psychic"],
["Golduck", "Water" , 75 , "No other types"]
]
}
TABLE_DATA
Expand Down
2 changes: 2 additions & 0 deletions lib/govuk/components/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def reset!
# +:default_warning_text_icon+ "!"
#
# +:require_summary_list_action_visually_hidden_text+ when true forces visually hidden text to be set for every action. It can still be explicitly skipped by passing in +nil+. Defaults to +false+
# +:enable_auto_table_scopes+ automatically adds a scope of 'col' to th elements in thead and 'row' to th elements in tbody.
DEFAULTS = {
default_back_link_text: 'Back',
default_breadcrumbs_collapse_on_mobile: false,
Expand Down Expand Up @@ -99,6 +100,7 @@ def reset!
default_link_new_tab_text: "(opens in new tab)",

require_summary_list_action_visually_hidden_text: false,
enable_auto_table_scopes: true,
}.freeze

DEFAULTS.each_key { |k| config_accessor(k) { DEFAULTS[k] } }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'spec_helper'

RSpec.describe(GovukComponent::TableComponent::CellComponent, type: :component) do
let(:text) { 'Content' }
let(:kwargs) { { text: text, header: true, parent: 'tbody' } }
let(:component_css_class) { 'govuk-table__cell' }

describe 'configuration' do
describe 'disabling automatic scopes' do
context "when enable_auto_table_scopes: true" do
subject! { render_inline(GovukComponent::TableComponent::CellComponent.new(**kwargs)) }

specify "renders a scopeless table cell" do
expect(rendered_content).to have_tag("th", text: "Content")
expect(html.at_css('th').attributes.keys).to match_array(%w(class scope))
end
end

context "when enable_auto_table_scopes: false" do
after { Govuk::Components.reset! }

before do
Govuk::Components.configure do |config|
config.enable_auto_table_scopes = false
end
end

subject! { render_inline(GovukComponent::TableComponent::CellComponent.new(**kwargs)) }

specify "renders a scopeless table cell" do
expect(rendered_content).to have_tag("th", text: "Content")
expect(html.at_css('th').attributes.keys).to match_array(%w(class))
end
end
end
end
end
Loading

0 comments on commit dba59da

Please sign in to comment.