Skip to content

Commit

Permalink
PLATUI-2897 enable passing of attributes to input form group wrappers (
Browse files Browse the repository at this point in the history
  • Loading branch information
ellamdav committed Mar 28, 2024
1 parent 91cac5f commit 12dd4f7
Show file tree
Hide file tree
Showing 65 changed files with 934 additions and 520 deletions.
32 changes: 32 additions & 0 deletions CHANGELOG.md
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
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
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))
}

val readsCountMessageClasses: Reads[String] =
(__ \ "countMessage" \ "classes").read[String].orElse(Reads.pure(""))

Expand Down
@@ -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 {

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))

}
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
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
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
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
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

0 comments on commit 12dd4f7

Please sign in to comment.