Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLATUI-2897 enable passing of attributes to input form group wrappers #288

Merged
merged 17 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ead934a
PLATUI-2897 add new FormGroup model; uplift GovukCheckboxes to add at…
ellamdav Mar 21, 2024
97c2a1d
PLATUI-2897 uplift GovukDateInput to add attributes to govuk-form-group
ellamdav Mar 21, 2024
3746cb5
PLATUI-2897 uplift GovukFileUpload to add attributes to govuk-form-group
ellamdav Mar 21, 2024
9113008
PLATUI-2897 uplift GovukInput to add attributes to govuk-form-group; …
ellamdav Mar 21, 2024
29fb518
PLATUI-2897 uplift GovukRadios to add attributes to govuk-form-group;…
ellamdav Mar 21, 2024
e752730
PLATUI-2897 uplift GovukSelect to add attributes to govuk-form-group
ellamdav Mar 21, 2024
8e135d0
PLATUI-2897 fixing intermittent integration test failures due to empt…
ellamdav Mar 22, 2024
203d62c
PLATUI-2897 uplift GovukTextarea to add attributes to govuk-form-group
ellamdav Mar 22, 2024
05cd088
PLATUI-2897 uplift GovukCharacterCount to add attributes to govuk-for…
ellamdav Mar 22, 2024
0aef8c3
PLATUI-2897 uplift HmrcCharacterCount to add attributes to govuk-form…
ellamdav Mar 25, 2024
54dd516
PLATUI-2897 extract GovukFormGroupSnippet to DRY up input components
ellamdav Mar 25, 2024
a922eeb
PLATUI-2897 extract GovukHintAndErrorMessageSnippet to DRY up input c…
ellamdav Mar 26, 2024
b832a94
PLATUI-2897 remove legacy formGroup reads/writes
ellamdav Mar 26, 2024
4244d9c
PLATUI-2897 address PR comments
ellamdav Mar 27, 2024
92cf552
PLATUI-2897 update CHANGELOG and add warning README in govuk helpers …
ellamdav Mar 27, 2024
7c0d475
PLATUI-2897 remove redundant quotes in `genHtmlString`
ellamdav Mar 27, 2024
bd0d7b6
PLATUI-2897 add `formGroupClasses` migration guidance to CHANGELOG
ellamdav Mar 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,38 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
For compatibility information see `govukFrontendVersion` and `hmrcFrontendVersion` in
[LibDependencies](project/LibDependencies.scala)

## [9.4.0] - 2024-03-27

### Changed

- Added support for custom attributes on `govuk-form-group` wrappers in various input components
- Updated form group customisation model to mirror govuk-frontend

> [!WARNING]
> If you are passing custom classes via `formGroupClasses` you must update these to use the new `FormGroup` model

eg. from

```scala
val foo = Checkboxes(
...
formGroupClasses = "my-custom classes",
...
)
```
to
```scala
val foo = Checkboxes(
...
formGroup = FormGroup(classes = Some("my-custom classes")),
...
)
```

### Compatible with

- [hmrc/hmrc-frontend v6.11.0](https://github.com/hmrc/hmrc-frontend/releases/tag/v6.11.0)
- [alphagov/govuk-frontend v5.2.0](https://github.com/alphagov/govuk-frontend/releases/tag/v5.2.0)

## [9.3.0] - 2024-03-25

Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ The parameters that can be passed into the `hmrcStandardPage` are as follows:

### Creating consistent page headings

> **Warning**
> [!WARNING]
> The [hmrc guidance for creating headings with a section (caption)](https://design.tax.service.gov.uk/hmrc-design-patterns/page-heading/) has recently changed. The following helpers are still available but this is no longer the recommended approach. Consult the linked documentation for examples of the new recommendation.

The `HmrcPageHeadingLabel` and `HmrcPageHeadingLegend` helpers let you use a label or legend as a page heading with a section (caption) displayed above it.
Expand Down Expand Up @@ -637,8 +637,7 @@ For example, you can add a template `WithSidebarOnLeft.scala.html` as below:

You can then inject this into your `Layout.scala.html` and partially apply the function as above.

> **Warning**
>
> [!WARNING]
> `FullWidthPageLayout` should only be used by internal services.
> The default fixed width layout should be used for all public services.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@ import play.twirl.api.Html
import scala.util.Try

object CommonJsonFormats {
val readsFormGroupClasses: Reads[String] =
(__ \ "formGroup" \ "classes").read[String].orElse(Reads.pure(""))

val writesFormGroupClasses: OWrites[String] = new OWrites[String] {
override def writes(classes: String): JsObject =
Json.obj("formGroup" -> Json.obj("classes" -> classes))
}

ellamdav marked this conversation as resolved.
Show resolved Hide resolved
val readsCountMessageClasses: Reads[String] =
(__ \ "countMessage" \ "classes").read[String].orElse(Reads.pure(""))

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2024 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.gov.hmrc.govukfrontend.views.viewmodels

import play.api.libs.functional.syntax._
import play.api.libs.json._

case class FormGroup(
classes: Option[String] = None,
attributes: Map[String, String] = Map.empty
)

object FormGroup {
ellamdav marked this conversation as resolved.
Show resolved Hide resolved

val empty: FormGroup = FormGroup()

implicit def jsonReads: Reads[FormGroup] =
(
(__ \ "classes").readNullable[String] and
(__ \ "attributes").readWithDefault[Map[String, String]](Map.empty)
)(FormGroup.apply _)

implicit def jsonWrites: OWrites[FormGroup] =
(
(__ \ "classes").writeNullable[String] and
(__ \ "attributes").write[Map[String, String]]
)(unlift(FormGroup.unapply))

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,39 @@ package uk.gov.hmrc.govukfrontend.views.viewmodels.charactercount

import play.api.libs.functional.syntax._
import play.api.libs.json._
import uk.gov.hmrc.govukfrontend.views.viewmodels.FormGroup
import uk.gov.hmrc.govukfrontend.views.viewmodels.CommonJsonFormats._
import uk.gov.hmrc.govukfrontend.views.viewmodels.errormessage.ErrorMessage
import uk.gov.hmrc.govukfrontend.views.viewmodels.hint.Hint
import uk.gov.hmrc.govukfrontend.views.viewmodels.label.Label
import uk.gov.hmrc.supportfrontend.views.IntString

/** Parameters to `GovukCharacterCount` Twirl template
*
* @param id the id of the `textarea` element
* @param name the name of the `textarea` element
* @param rows height of the `textarea` in rows
* @param value optional initial value of the `textarea`
* @param maxLength optional maximum length, in characters, of the text in the `textarea`
* @param maxWords optional maximum number of words in the `textarea`
* @param threshold optional threshold, in characters, for the `textarea`
* @param label optional `Label` for the control
* @param hint optional `Hint` for the control
* @param errorMessage optional `ErrorMessage` to display
* @param formGroup additional CSS classes/attributes/etc. to apply to the form group
* @param classes optional additional CSS classes to apply to the `textarea`
* @param attributes optional additional HTML attributes to apply to the `textarea`
* @param countMessageClasses optional additional CSS classes to apply to the max length/word count message
* @param charactersUnderLimitText optional text to display when the character count is under the limit
* (defaults to "You can enter up to {maxLength} characters")
* @param charactersAtLimitText optional text to display when the character count is at the limit
* @param charactersOverLimitText optional text to display when the character count is over the limit
* @param wordsUnderLimitText optional text to display when the word count is under the limit
* (defaults to "You can enter up to {maxWords} words")
* @param wordsAtLimitText optional text to display when the word count is at the limit
* @param wordsOverLimitText optional text to display when the word count is over the limit
* @param textareaDescriptionText optional text to display under the textarea
*/
case class CharacterCount(
id: String = "",
name: String = "",
Expand All @@ -35,7 +62,7 @@ case class CharacterCount(
label: Label = Label(),
hint: Option[Hint] = None,
errorMessage: Option[ErrorMessage] = None,
formGroupClasses: String = "",
formGroup: FormGroup = FormGroup.empty,
classes: String = "",
attributes: Map[String, String] = Map.empty,
countMessageClasses: String = "",
Expand Down Expand Up @@ -64,7 +91,7 @@ object CharacterCount {
(__ \ "label").readWithDefault[Label](defaultObject.label) and
(__ \ "hint").readNullable[Hint] and
(__ \ "errorMessage").readNullable[ErrorMessage] and
readsFormGroupClasses and
(__ \ "formGroup").readWithDefault[FormGroup](defaultObject.formGroup) and
(__ \ "classes").readWithDefault[String](defaultObject.classes) and
(__ \ "attributes").readWithDefault[Map[String, String]](defaultObject.attributes) and
readsCountMessageClasses and
Expand All @@ -89,7 +116,7 @@ object CharacterCount {
(__ \ "label").write[Label] and
(__ \ "hint").writeNullable[Hint] and
(__ \ "errorMessage").writeNullable[ErrorMessage] and
writesFormGroupClasses and
(__ \ "formGroup").write[FormGroup] and
(__ \ "classes").write[String] and
(__ \ "attributes").write[Map[String, String]] and
writesCountMessageClasses and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ import play.api.libs.functional.syntax._
import play.api.libs.json._
import uk.gov.hmrc.govukfrontend.views.html.components._
import uk.gov.hmrc.govukfrontend.views.viewmodels.CommonJsonFormats._
import uk.gov.hmrc.govukfrontend.views.viewmodels.FormGroup

/** Parameters to `GovukCheckboxes` Twirl template
*
* @param describedBy optional `aria-describedby` attribute for the `input` element
* @param fieldset optional `Fieldset` used to wrap the checkboxes control
* @param hint optional `Hint` for the control
* @param errorMessage optional `ErrorMessage` to display
* @param formGroupClasses optional additional CSS classes to apply to the form group
* @param formGroup additional CSS classes/attributes/etc. to apply to the form group
* @param idPrefix optional id prefix to use for hint & error elements (defaults to `name`)
* @param name the name of the `input` element
* @param items sequence of `CheckboxItem`s
Expand All @@ -41,7 +42,7 @@ case class Checkboxes(
fieldset: Option[Fieldset] = None,
hint: Option[Hint] = None,
errorMessage: Option[ErrorMessage] = None,
formGroupClasses: String = "",
formGroup: FormGroup = FormGroup.empty,
idPrefix: Option[String] = None,
name: String = "",
items: Seq[CheckboxItem] = Nil,
Expand All @@ -60,7 +61,7 @@ object Checkboxes {
(__ \ "fieldset").readNullable[Fieldset] and
(__ \ "hint").readNullable[Hint] and
(__ \ "errorMessage").readNullable[ErrorMessage] and
readsFormGroupClasses and
(__ \ "formGroup").readWithDefault[FormGroup](defaultObject.formGroup) and
(__ \ "idPrefix").readNullable[String] and
(__ \ "name").readWithDefault[String](defaultObject.name) and
(__ \ "items").readWithDefault[Seq[CheckboxItem]](defaultObject.items)(forgivingSeqReads[CheckboxItem]) and
Expand All @@ -75,7 +76,7 @@ object Checkboxes {
(__ \ "fieldset").writeNullable[Fieldset] and
(__ \ "hint").writeNullable[Hint] and
(__ \ "errorMessage").writeNullable[ErrorMessage] and
writesFormGroupClasses and
(__ \ "formGroup").write[FormGroup] and
(__ \ "idPrefix").writeNullable[String] and
(__ \ "name").write[String] and
(__ \ "items").write[Seq[CheckboxItem]] and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,27 @@ package uk.gov.hmrc.govukfrontend.views.viewmodels.dateinput
import play.api.libs.functional.syntax._
import play.api.libs.json._
import uk.gov.hmrc.govukfrontend.views.html.components._
import uk.gov.hmrc.govukfrontend.views.viewmodels.CommonJsonFormats._
import uk.gov.hmrc.govukfrontend.views.viewmodels.FormGroup

/** Parameters to `GovukDateInput` Twirl template
*
* @param id `id` attribute for the wrapper `div`
* @param namePrefix optional name prefix for each of the inputs in the date control
* @param items sequence of `InputItem`s
* @param hint optional `Hint` for the control
* @param errorMessage optional `ErrorMessage` to display
* @param formGroup additional CSS classes/attributes/etc. to apply to the form group
* @param fieldset optional `Fieldset` used to wrap the date input control
* @param classes optional additional CSS classes to apply to the wrapper `div`
* @param attributes optional additional HTML attributes to apply to the wrapper `div`
*/
case class DateInput(
id: String = "",
namePrefix: Option[String] = None,
items: Seq[InputItem] = Seq.empty,
hint: Option[Hint] = None,
errorMessage: Option[ErrorMessage] = None,
formGroupClasses: String = "",
formGroup: FormGroup = FormGroup.empty,
fieldset: Option[Fieldset] = None,
classes: String = "",
attributes: Map[String, String] = Map.empty
Expand All @@ -44,7 +56,7 @@ object DateInput {
(__ \ "items").readWithDefault[Seq[InputItem]](defaultObject.items) and
(__ \ "hint").readNullable[Hint] and
(__ \ "errorMessage").readNullable[ErrorMessage] and
readsFormGroupClasses and
(__ \ "formGroup").readWithDefault[FormGroup](defaultObject.formGroup) and
(__ \ "fieldset").readNullable[Fieldset] and
(__ \ "classes").readWithDefault[String](defaultObject.classes) and
(__ \ "attributes").readWithDefault[Map[String, String]](defaultObject.attributes)
Expand All @@ -57,7 +69,7 @@ object DateInput {
(__ \ "items").write[Seq[InputItem]] and
(__ \ "hint").writeNullable[Hint] and
(__ \ "errorMessage").writeNullable[ErrorMessage] and
writesFormGroupClasses and
(__ \ "formGroup").write[FormGroup] and
(__ \ "fieldset").writeNullable[Fieldset] and
(__ \ "classes").write[String] and
(__ \ "attributes").write[Map[String, String]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,25 @@ package uk.gov.hmrc.govukfrontend.views.viewmodels.fileupload

import play.api.libs.functional.syntax._
import play.api.libs.json._
import uk.gov.hmrc.govukfrontend.views.viewmodels.CommonJsonFormats._
import uk.gov.hmrc.govukfrontend.views.viewmodels.FormGroup
import uk.gov.hmrc.govukfrontend.views.viewmodels.errormessage.ErrorMessage
import uk.gov.hmrc.govukfrontend.views.viewmodels.hint.Hint
import uk.gov.hmrc.govukfrontend.views.viewmodels.label.Label

/** Parameters to `GovukFileUpload` Twirl template
*
* @param name `name` attribute for the `input`
* @param id `id` attribute for the `input`
* @param value optional `value` attribute for the `input`
* @param describedBy optional `aria-describedby` attribute for the `input`
* @param label optional `Label` for the control
* @param hint optional `Hint` for the control
* @param errorMessage optional `ErrorMessage` to display
* @param formGroup additional CSS classes/attributes/etc. to apply to the form group
* @param classes optional additional CSS classes to apply to the `input`
* @param attributes optional additional HTML attributes to apply to the `input`
* @param disabled optional `disabled` attribute for the `input`
*/
case class FileUpload(
name: String = "",
id: String = "",
Expand All @@ -31,7 +45,7 @@ case class FileUpload(
label: Label = Label(),
hint: Option[Hint] = None,
errorMessage: Option[ErrorMessage] = None,
formGroupClasses: String = "",
formGroup: FormGroup = FormGroup.empty,
classes: String = "",
attributes: Map[String, String] = Map.empty,
disabled: Option[Boolean] = None
Expand All @@ -50,7 +64,7 @@ object FileUpload {
(__ \ "label").readWithDefault[Label](defaultObject.label) and
(__ \ "hint").readNullable[Hint] and
(__ \ "errorMessage").readNullable[ErrorMessage] and
readsFormGroupClasses and
(__ \ "formGroup").readWithDefault[FormGroup](defaultObject.formGroup) and
(__ \ "classes").readWithDefault[String](defaultObject.classes) and
(__ \ "attributes").readWithDefault[Map[String, String]](defaultObject.attributes) and
(__ \ "disabled").readNullable[Boolean]
Expand All @@ -65,7 +79,7 @@ object FileUpload {
(__ \ "label").write[Label] and
(__ \ "hint").writeNullable[Hint] and
(__ \ "errorMessage").writeNullable[ErrorMessage] and
writesFormGroupClasses and
(__ \ "formGroup").write[FormGroup] and
(__ \ "classes").write[String] and
(__ \ "attributes").write[Map[String, String]] and
(__ \ "disabled").writeNullable[Boolean]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,32 @@ package uk.gov.hmrc.govukfrontend.views.viewmodels.input

import play.api.libs.functional.syntax._
import play.api.libs.json._
import uk.gov.hmrc.govukfrontend.views.viewmodels.CommonJsonFormats._
import uk.gov.hmrc.govukfrontend.views.viewmodels.FormGroup
import uk.gov.hmrc.govukfrontend.views.viewmodels.errormessage.ErrorMessage
import uk.gov.hmrc.govukfrontend.views.viewmodels.hint.Hint
import uk.gov.hmrc.govukfrontend.views.viewmodels.label.Label

/** Parameters to `GovukInput` Twirl template
*
* @param id `id` attribute for the `input`
* @param name `name` attribute for the `input`
* @param inputType `type` attribute for the `input`
* @param inputmode optional `inputmode` attribute for the `input`
* @param describedBy optional `aria-describedby` attribute for the `input`
* @param value optional `value` attribute for the `input`
* @param label optional `Label` for the control
* @param hint optional `Hint` for the control
* @param errorMessage optional `ErrorMessage` to display
* @param formGroup additional CSS classes/attributes/etc. to apply to the form group
* @param classes optional additional CSS classes to apply to the `input`
* @param autocomplete optional `autocomplete` attribute for the `input`
* @param pattern optional `pattern` attribute for the `input`
* @param attributes optional additional HTML attributes to apply to the `input`
* @param spellcheck optional `spellcheck` attribute for the `input`
* @param prefix optional content to display immediately before the `input`
* @param suffix optional content to display immediately after the `input`
* @param disabled optional `disabled` attribute for the `input`
*/
case class Input(
id: String = "",
name: String = "",
Expand All @@ -33,7 +54,7 @@ case class Input(
label: Label = Label(),
hint: Option[Hint] = None,
errorMessage: Option[ErrorMessage] = None,
formGroupClasses: String = "",
formGroup: FormGroup = FormGroup.empty,
classes: String = "",
autocomplete: Option[String] = None,
pattern: Option[String] = None,
Expand All @@ -59,7 +80,7 @@ object Input {
(__ \ "label").readWithDefault[Label](defaultObject.label) and
(__ \ "hint").readNullable[Hint] and
(__ \ "errorMessage").readNullable[ErrorMessage] and
readsFormGroupClasses and
(__ \ "formGroup").readWithDefault[FormGroup](defaultObject.formGroup) and
(__ \ "classes").readWithDefault[String](defaultObject.classes) and
(__ \ "autocomplete").readNullable[String] and
(__ \ "pattern").readNullable[String] and
Expand All @@ -81,7 +102,7 @@ object Input {
(__ \ "label").write[Label] and
(__ \ "hint").writeNullable[Hint] and
(__ \ "errorMessage").writeNullable[ErrorMessage] and
writesFormGroupClasses and
(__ \ "formGroup").write[FormGroup] and
(__ \ "classes").write[String] and
(__ \ "autocomplete").writeNullable[String] and
(__ \ "pattern").writeNullable[String] and
Expand Down