Implement advanced check, radio form controls

This commit is contained in:
Alexander Brandon Coles
2025-11-14 13:24:39 +00:00
parent f19a585550
commit 2c3a84df04
17 changed files with 941 additions and 0 deletions
@@ -171,3 +171,57 @@ input[type="number"]
&::-webkit-outer-spin-button
-webkit-appearance: none
margin: 0
.FormControl-advanced-check-group-wrap,
.FormControl-advanced-radio-group-wrap
& fieldset
padding: 0
margin: 0
border: 0
.FormControl-advanced-check-group-list,
.FormControl-advanced-radio-group-list
display: grid
grid-template-columns: repeat(2, 1fr)
gap: var(--base-size-12) var(--base-size-16)
@media screen and (max-width: $breakpoint-sm)
grid-template-columns: 1fr
.FormControl-advanced-checkbox-wrap,
.FormControl-advanced-radio-wrap
display: flex
background-color: var(--bgColor-inset)
border: var(--borderWidth-thin, 1px) solid var(--borderColor-default)
border-radius: var(--borderRadius-medium)
&:has(input:hover)
background-color: var(--bgColor-accent-muted)
border-color: var(--borderColor-accent-muted)
&:has(input:checked)
background-color: var(--bgColor-accent-muted)
border-color: var(--control-checked-borderColor-rest)
& .FormControl-label
display: block
flex: 1
cursor: pointer
.FormControl-advanced-checkbox-content,
.FormControl-advanced-radio-content
display: grid
grid-template-columns: auto min-content
gap: var(--base-size-8)
padding: var(--base-size-12)
.FormControl-advanced-checkbox-label-row,
.FormControl-advanced-radio-label-row
display: inline-grid
grid-template-columns: min-content auto
gap: var(--base-size-8)
color: var(--fgColor-accent)
.FormControl-advanced-checkbox-icon,
.FormControl-advanced-radio-icon
fill: var(--fgColor-accent)
@@ -0,0 +1,26 @@
<%= content_tag(:div, class: "FormControl-advanced-checkbox-wrap", hidden: @input.hidden?) do %>
<%= builder.label(@input.name, **@input.label_arguments) do %>
<div class="FormControl-advanced-checkbox-content">
<div>
<div class="FormControl-advanced-checkbox-label-row">
<%= builder.check_box(@input.name, @input.input_arguments, checked_value, unchecked_value) %>
<%= @input.label %>
</div>
<% if @input.form_control? %>
<div class="mt-1">
<%= render(Caption.new(input: @input)) %>
</div>
<% end %>
</div>
<% if @input.icon.present? %>
<%=
inline_svg_tag(
@input.icon,
class: "FormControl-advanced-checkbox-icon",
aria_hidden: true
)
%>
<% end %>
</div>
<% end %>
<% end %>
@@ -0,0 +1,40 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Primer
module OpenProject
module Forms
# :nodoc:
class AdvancedCheckBox < Primer::Forms::CheckBox
include InlineSvg::ActionView::Helpers
end
end
end
end
@@ -0,0 +1,22 @@
<div class="FormControl-advanced-check-group-wrap">
<%= content_tag(:fieldset, **@input.input_arguments) do %>
<% if @input.label %>
<%= content_tag(:legend, **@input.label_arguments) do %>
<%= @input.label %>
<% end %>
<% end %>
<div class="mb-2">
<%= render(Caption.new(input: @input)) %>
</div>
<%= render(SpacingWrapper.new) do %>
<div class="FormControl-advanced-check-group-list">
<% @input.check_boxes.each do |check_box| %>
<%= render(check_box.to_component) %>
<% end %>
</div>
<% end %>
<% end %>
<div class="mt-2">
<%= render(ValidationMessage.new(input: @input)) %>
</div>
</div>
@@ -0,0 +1,39 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Primer
module OpenProject
module Forms
# :nodoc:
class AdvancedCheckBoxGroup < Primer::Forms::CheckBoxGroup
end
end
end
end
@@ -0,0 +1,26 @@
<%= content_tag(:div, class: "FormControl-advanced-radio-wrap", hidden: @input.hidden?) do %>
<%= builder.label(@input.name, value: @input.value, **@input.label_arguments) do %>
<div class="FormControl-advanced-radio-content">
<div>
<div class="FormControl-advanced-radio-label-row">
<%= builder.radio_button(@input.name, @input.value, **@input.input_arguments) %>
<%= @input.label %>
</div>
<% if @input.form_control? %>
<div class="mt-1">
<%= render(Caption.new(input: @input)) %>
</div>
<% end %>
</div>
<% if @input.icon.present? %>
<%=
inline_svg_tag(
@input.icon,
class: "FormControl-advanced-radio-icon",
aria_hidden: true
)
%>
<% end %>
</div>
<% end %>
<% end %>
@@ -0,0 +1,40 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Primer
module OpenProject
module Forms
# :nodoc:
class AdvancedRadioButton < Primer::Forms::RadioButton
include InlineSvg::ActionView::Helpers
end
end
end
end
@@ -0,0 +1,22 @@
<div class="FormControl-advanced-radio-group-wrap">
<%= content_tag(:fieldset, role: "radiogroup", **@input.input_arguments) do %>
<% if @input.label %>
<%= content_tag(:legend, **@input.label_arguments) do %>
<%= @input.label %>
<% end %>
<% end %>
<div class="mb-2">
<%= render(Caption.new(input: @input)) %>
</div>
<%= render(SpacingWrapper.new) do %>
<div class="FormControl-advanced-radio-group-list">
<% @input.radio_buttons.each do |radio_button| %>
<%= render(radio_button.to_component) %>
<% end %>
</div>
<% end %>
<% end %>
<div class="mt-2">
<%= render(ValidationMessage.new(input: @input)) %>
</div>
</div>
@@ -0,0 +1,39 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Primer
module OpenProject
module Forms
# :nodoc:
class AdvancedRadioButtonGroup < Primer::Forms::RadioButtonGroup
end
end
end
end
@@ -0,0 +1,87 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Primer
module OpenProject
module Forms
module Dsl
# :nodoc:
class AdvancedCheckBoxGroupInput < Primer::Forms::Dsl::Input
attr_reader :name, :label, :check_boxes
def initialize(name: nil, label: nil, **system_arguments)
@name = name
@label = label
@check_boxes = []
super(**system_arguments)
yield(self) if block_given?
end
def to_component
AdvancedCheckBoxGroup.new(input: self)
end
def type
:check_box_group
end
def focusable?
true
end
def autofocus!
@check_boxes.first&.autofocus!
end
def check_box(**system_arguments, &)
args = {
name: @name,
builder: @builder,
form: @form,
scheme: scheme,
disabled: disabled?,
**system_arguments
}
@check_boxes << AdvancedCheckBoxInput.new(**args, &)
end
private
def scheme
@name ? :array : :boolean
end
end
end
end
end
end
@@ -0,0 +1,87 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Primer
module OpenProject
module Forms
module Dsl
# :nodoc:
class AdvancedCheckBoxInput < Primer::Forms::Dsl::Input
DEFAULT_SCHEME = :boolean
SCHEMES = [DEFAULT_SCHEME, :array].freeze
attr_reader :name, :label, :value, :unchecked_value, :scheme, :icon
def initialize(name:, label:, value: nil, unchecked_value: nil, scheme: DEFAULT_SCHEME, icon: nil, **system_arguments)
raise ArgumentError, "Check box scheme must be one of #{SCHEMES.join(', ')}" unless SCHEMES.include?(scheme)
raise ArgumentError, "Check box needs an explicit value if scheme is array" if scheme == :array && value.nil?
@name = name
@label = label
@value = value
@unchecked_value = unchecked_value
@scheme = scheme
@icon = icon
super(**system_arguments)
yield(self) if block_given?
end
# check boxes cannot be invalid, as both checked and unchecked are valid states
# :nocov:
def valid?
true
end
# :nocov:
def to_component
AdvancedCheckBox.new(input: self)
end
def type
:check_box
end
def supports_validation?
false
end
def values_disambiguate_template_names?
# Check boxes submitted as an array all have the same name, so we return true here
# to ensure different caption templates can be attached to individual check box inputs.
@scheme == :array
end
end
end
end
end
end
@@ -0,0 +1,75 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Primer
module OpenProject
module Forms
module Dsl
# :nodoc:
class AdvancedRadioButtonGroupInput < Primer::Forms::Dsl::Input
attr_reader :name, :label, :radio_buttons
def initialize(name:, label: nil, **system_arguments)
@name = name
@label = label
@radio_buttons = []
super(**system_arguments)
yield(self) if block_given?
end
def to_component
AdvancedRadioButtonGroup.new(input: self)
end
def type
:radio_button_group
end
def autofocus!
@radio_buttons.first&.autofocus!
end
def focusable?
true
end
def radio_button(**system_arguments, &)
@radio_buttons << AdvancedRadioButtonInput.new(
builder: @builder, form: @form, name: @name, disabled: disabled?,
**system_arguments, &
)
end
end
end
end
end
end
@@ -0,0 +1,78 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Primer
module OpenProject
module Forms
module Dsl
# :nodoc:
class AdvancedRadioButtonInput < Primer::Forms::Dsl::Input
attr_reader :name, :value, :label, :icon
def initialize(name:, value:, label:, icon: nil, **system_arguments)
@name = name
@value = value
@label = label
@icon = icon
super(**system_arguments)
yield(self) if block_given?
end
# radio buttons cannot be invalid, as both selected and unselected are valid states
# :nocov:
def valid?
true
end
# :nocov:
def to_component
AdvancedRadioButton.new(input: self)
end
# :nocov:
def type
:radio_button
end
# :nocov:
def supports_validation?
false
end
def values_disambiguate_template_names?
true
end
end
end
end
end
end
@@ -21,6 +21,14 @@ module Primer
super(**decorate_options(**), &)
end
def advanced_radio_button_group(**, &)
add_input AdvancedRadioButtonGroupInput.new(builder:, form:, **decorate_options(**), &)
end
def advanced_check_box_group(**, &)
add_input AdvancedCheckBoxGroupInput.new(builder:, form:, **decorate_options(**), &)
end
def autocompleter(**, &)
add_input AutocompleterInput.new(builder:, form:, **decorate_options(**), &)
end
@@ -0,0 +1,142 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
#
require "spec_helper"
RSpec.describe Primer::OpenProject::Forms::AdvancedCheckBoxGroup, type: :forms do
include ViewComponent::TestHelpers
describe "rendering" do
let(:params) { {} }
let(:model) { build_stubbed(:comment) }
def render_form
render_in_view_context(model, params) do |model, params|
primer_form_with(url: "/foo", model:) do |f|
render_inline_form(f) do |check_form|
check_form.advanced_check_box_group(
name: :ultimate_answer,
label: "Ultimate answer",
**params
) do |group|
group.check_box(
value: "one",
label: "One",
caption: "Pick me",
icon: "icon_logo.svg"
)
group.check_box(
value: "two",
label: "Two",
caption: "Don't pick me",
icon: "icon_logo.svg"
)
group.check_box(
value: "three",
label: "Three",
icon: nil
)
end
end
end
end
end
subject(:rendered_form) do
render_form
page
end
it "renders the fieldset" do
expect(rendered_form).to have_selector :fieldset, "Ultimate answer"
end
it "renders the checkboxes", :aggregate_failures do
expect(rendered_form).to have_field "One", type: :checkbox, fieldset: "Ultimate answer"
expect(rendered_form).to have_field "Two", type: :checkbox, fieldset: "Ultimate answer"
expect(rendered_form).to have_field "Three", type: :checkbox, fieldset: "Ultimate answer"
end
it "renders icons" do
expect(rendered_form).to have_element :svg, count: 2, aria: { hidden: true }
end
it "renders captions", :aggregate_failures do
expect(rendered_form).to have_css ".FormControl-caption", count: 2
expect(rendered_form).to have_css ".FormControl-caption", text: "Pick me"
expect(rendered_form).to have_css ".FormControl-caption", text: "Don't pick me"
end
end
describe "standard checkbox group compatibility" do
specify "hidden checkbox group", :aggregate_failures do
render_in_view_context do
primer_form_with(url: "/foo") do |f|
render_inline_form(f) do |check_form|
check_form.advanced_check_box_group(label: "Foobar", hidden: true) do |check_group|
check_group.check_box(name: :foo, label: "Foo")
end
end
end
end
expect(page).to have_selector :fieldset, visible: :hidden
expect(page).to have_css ".FormControl-advanced-checkbox-wrap", visible: :hidden
end
specify "disabled checkbox group disables constituent checkboxes" do
render_in_view_context do
primer_form_with(url: "/foo") do |f|
render_inline_form(f) do |check_form|
check_form.advanced_check_box_group(label: "Foobar", disabled: true) do |check_group|
check_group.check_box(name: :foo, label: "Foo")
end
end
end
end
expect(page).to have_css ".FormControl-advanced-checkbox-wrap input[disabled]"
end
specify "checkbox can be individually disabled in group" do
render_in_view_context do
primer_form_with(url: "/foo") do |f|
render_inline_form(f) do |check_form|
check_form.advanced_check_box_group(label: "Foobar") do |check_group|
check_group.check_box(name: :foo, label: "Foo", disabled: true)
end
end
end
end
expect(page).to have_css ".FormControl-advanced-checkbox-wrap input[disabled]"
end
end
end
@@ -0,0 +1,142 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
#
require "spec_helper"
RSpec.describe Primer::OpenProject::Forms::AdvancedRadioButtonGroup, type: :forms do
include ViewComponent::TestHelpers
describe "rendering" do
let(:params) { {} }
let(:model) { build_stubbed(:comment) }
def render_form
render_in_view_context(model, params) do |model, params|
primer_form_with(url: "/foo", model:) do |f|
render_inline_form(f) do |radio_form|
radio_form.advanced_radio_button_group(
name: :ultimate_answer,
label: "Ultimate answer",
**params
) do |group|
group.radio_button(
value: "one",
label: "One",
caption: "Pick me",
icon: "icon_logo.svg"
)
group.radio_button(
value: "two",
label: "Two",
caption: "Don't pick me",
icon: "icon_logo.svg"
)
group.radio_button(
value: "three",
label: "Three",
icon: nil
)
end
end
end
end
end
subject(:rendered_form) do
render_form
page
end
it "renders the fieldset" do
expect(rendered_form).to have_selector :fieldset, "Ultimate answer", role: "radiogroup"
end
it "renders the radio buttons", :aggregate_failures do
expect(rendered_form).to have_field "One", type: :radio, fieldset: "Ultimate answer"
expect(rendered_form).to have_field "Two", type: :radio, fieldset: "Ultimate answer"
expect(rendered_form).to have_field "Three", type: :radio, fieldset: "Ultimate answer"
end
it "renders icons" do
expect(rendered_form).to have_element :svg, count: 2, aria: { hidden: true }
end
it "renders captions", :aggregate_failures do
expect(rendered_form).to have_css ".FormControl-caption", count: 2
expect(rendered_form).to have_css ".FormControl-caption", text: "Pick me"
expect(rendered_form).to have_css ".FormControl-caption", text: "Don't pick me"
end
end
describe "standard radio button group compatibility" do
specify "hidden radio button group", :aggregate_failures do
render_in_view_context do
primer_form_with(url: "/foo") do |f|
render_inline_form(f) do |radio_form|
radio_form.advanced_radio_button_group(name: :foobar, label: "Foobar", hidden: true) do |radio_group|
radio_group.radio_button(name: :foo, value: "Foo", label: "Foo")
end
end
end
end
expect(page).to have_selector :fieldset, visible: :hidden
expect(page).to have_css ".FormControl-advanced-radio-wrap", visible: :hidden
end
specify "disabled radio group disables constituent radios" do
render_in_view_context do
primer_form_with(url: "/foo") do |f|
render_inline_form(f) do |radio_form|
radio_form.advanced_radio_button_group(name: :foobar, label: "Foobar", disabled: true) do |radio_group|
radio_group.radio_button(name: :foo, value: "Foo", label: "Foo")
end
end
end
end
expect(page).to have_css ".FormControl-advanced-radio-wrap input[disabled]"
end
specify "radio can be individually disabled in group" do
render_in_view_context do
primer_form_with(url: "/foo") do |f|
render_inline_form(f) do |radio_form|
radio_form.advanced_radio_button_group(name: :foobar, label: "Foobar") do |radio_group|
radio_group.radio_button(name: :foo, value: "Foo", label: "Foo", disabled: true)
end
end
end
end
expect(page).to have_css ".FormControl-advanced-radio-wrap input[disabled]"
end
end
end
@@ -113,6 +113,20 @@ RSpec.describe Primer::OpenProject::Forms::Dsl::InputMethods, type: :forms do
include_examples "input class", Primer::Forms::Dsl::CheckBoxGroupInput
it_behaves_like "supporting help texts"
end
describe "#advanced_radio_button_group" do
let(:field_group) { form_dsl.advanced_radio_button_group(name:, label:, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::AdvancedRadioButtonGroupInput
it_behaves_like "supporting help texts"
end
describe "#advanced_check_box_group" do
let(:field_group) { form_dsl.advanced_check_box_group(name:, label:, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::AdvancedCheckBoxGroupInput
it_behaves_like "supporting help texts"
end
end
describe "#separator" do