diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 9551f08f..18330060 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -46,5 +46,5 @@ jobs: run: | (cd tests/utils && nohup python -m flask run --port 3000 &) wait-for-it localhost:3000 - ./govuk-frontend-diff http://localhost:3000 --govuk-frontend-version=v5.1.0 --exclude page-template --ci + ./govuk-frontend-diff http://localhost:3000 --govuk-frontend-version=v5.4.0 --exclude page-template --ci diff --git a/CHANGELOG.md b/CHANGELOG.md index 21f870bd..802973d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased](https://github.com/LandRegistry/govuk-frontend-jinja/compare/3.0.0...main) +## [Unreleased](https://github.com/LandRegistry/govuk-frontend-jinja/compare/3.1.0...main) + +## [3.1.0](https://github.com/LandRegistry/govuk-frontend-jinja/releases/tag/3.1.0) - 28/05/2024 + +### Added + +- [GOV.UK Frontend v5.4.0](https://github.com/alphagov/govuk-frontend/releases/tag/v5.4.0) support ## [3.0.0](https://github.com/LandRegistry/govuk-frontend-jinja/releases/tag/3.0.0) - 08/02/2024 diff --git a/README.md b/README.md index bdd13fe6..cb7f83b0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # GOV.UK Frontend Jinja Macros [![PyPI version](https://badge.fury.io/py/govuk-frontend-jinja.svg)](https://pypi.org/project/govuk-frontend-jinja/) -![govuk-frontend 5.1.0](https://img.shields.io/badge/govuk--frontend%20version-5.1.0-005EA5?logo=gov.uk&style=flat) +![govuk-frontend 5.4.0](https://img.shields.io/badge/govuk--frontend%20version-5.4.0-005EA5?logo=gov.uk&style=flat) [![Python package](https://github.com/LandRegistry/govuk-frontend-jinja/actions/workflows/python-package.yml/badge.svg)](https://github.com/LandRegistry/govuk-frontend-jinja/actions/workflows/python-package.yml) **GOV.UK Frontend Jinja is a [community tool](https://design-system.service.gov.uk/community/resources-and-tools/) of the [GOV.UK Design System](https://design-system.service.gov.uk/). The Design System team is not responsible for it and cannot support you with using it. Contact the [maintainers](#contributors) directly if you need [help](#support) or you want to request a feature.** @@ -16,6 +16,7 @@ The following table shows the version of GOV.UK Frontend Jinja that you should u | GOV.UK Frontend Jinja Version | Target GOV.UK Frontend Version | | ----------------------------- | ------------------------------ | +| [3.1.0](https://github.com/LandRegistry/govuk-frontend-jinja/releases/tag/3.1.0) | [5.4.0](https://github.com/alphagov/govuk-frontend/releases/tag/v5.4.0) | | [3.0.0](https://github.com/LandRegistry/govuk-frontend-jinja/releases/tag/3.0.0) | [5.1.0](https://github.com/alphagov/govuk-frontend/releases/tag/v5.1.0) | | [2.8.0](https://github.com/LandRegistry/govuk-frontend-jinja/releases/tag/2.8.0) | [4.8.0](https://github.com/alphagov/govuk-frontend/releases/tag/v4.8.0) | | [2.7.0](https://github.com/LandRegistry/govuk-frontend-jinja/releases/tag/2.7.0) | [4.7.0](https://github.com/alphagov/govuk-frontend/releases/tag/v4.7.0) | diff --git a/govuk_frontend_jinja/templates/components/accordion/macro.html b/govuk_frontend_jinja/templates/components/accordion/macro.html index b3b44d52..3fa1f2aa 100644 --- a/govuk_frontend_jinja/templates/components/accordion/macro.html +++ b/govuk_frontend_jinja/templates/components/accordion/macro.html @@ -1,4 +1,5 @@ {% macro govukAccordion(params) %} +{% from "govuk_frontend_jinja/macros/attributes.html" import govukAttributes %} {% from "govuk_frontend_jinja/macros/i18n.html" import govukI18nAttributes %} {%- macro _accordionItem(params, item, index) %} @@ -60,7 +61,7 @@ }) -}} {%- if params.rememberExpanded is not undefined %} data-remember-expanded="{{ params.rememberExpanded | escape | lower }}"{% endif %} - {%- for attribute, value in (params.attributes.items() if params.attributes else {}.items()) %} {{ attribute }}="{{ value }}"{% endfor %}> + {{- govukAttributes(params.attributes) }}> {% for item in params['items'] %} {% if item %}{{ _accordionItem(params, item, loop.index) }}{% endif %} {% endfor %} diff --git a/govuk_frontend_jinja/templates/components/back-link/macro.html b/govuk_frontend_jinja/templates/components/back-link/macro.html index cac39ca9..f89e4e8e 100644 --- a/govuk_frontend_jinja/templates/components/back-link/macro.html +++ b/govuk_frontend_jinja/templates/components/back-link/macro.html @@ -1,4 +1,8 @@ {% macro govukBackLink(params) %} +{% from "govuk_frontend_jinja/macros/attributes.html" import govukAttributes -%} + {{ (params.html | safe if params.html else (params.text if params.text else 'Back')) }} + {{- govukAttributes(params.attributes) }}> + {{- params.html | safe if params.html else (params.text if params.text else "Back") -}} + {% endmacro %} diff --git a/govuk_frontend_jinja/templates/components/breadcrumbs/macro.html b/govuk_frontend_jinja/templates/components/breadcrumbs/macro.html index b1ddf544..1fc37155 100644 --- a/govuk_frontend_jinja/templates/components/breadcrumbs/macro.html +++ b/govuk_frontend_jinja/templates/components/breadcrumbs/macro.html @@ -1,21 +1,23 @@ {% macro govukBreadcrumbs(params) %} -{# Set classes for this component #} +{% from "govuk_frontend_jinja/macros/attributes.html" import govukAttributes %} + +{#- Set classes for this component #} {%- set classNames = "govuk-breadcrumbs" -%} {% if params.classes %} - {% set classNames = classNames + " " + params.classes %} + {% set classNames = classNames ~ " " ~ params.classes %} {% endif -%} {% if params.collapseOnMobile %} - {% set classNames = classNames + " govuk-breadcrumbs--collapse-on-mobile" %} + {% set classNames = classNames ~ " govuk-breadcrumbs--collapse-on-mobile" %} {% endif -%} -
+
    {% for item in params['items'] %} {% if item.href %}
  1. - + {{- item.html | safe if item.html else item.text -}}
  2. diff --git a/govuk_frontend_jinja/templates/components/button/macro.html b/govuk_frontend_jinja/templates/components/button/macro.html index 1680c2e3..12842b83 100644 --- a/govuk_frontend_jinja/templates/components/button/macro.html +++ b/govuk_frontend_jinja/templates/components/button/macro.html @@ -1,13 +1,15 @@ {% macro govukButton(params) %} -{# Set classes for this component #} +{% from "govuk_frontend_jinja/macros/attributes.html" import govukAttributes %} + +{#- Set classes for this component #} {%- set classNames = "govuk-button" -%} {%- if params.classes %} - {% set classNames = classNames + " " + params.classes %} + {% set classNames = classNames ~ " " ~ params.classes %} {% endif %} {%- if params.isStartButton %} - {% set classNames = classNames + " govuk-button--start" %} + {% set classNames = classNames ~ " govuk-button--start" %} {% endif %} {#- Determine type of element to use, if not explicitly set #} @@ -32,7 +34,7 @@ {#- Define common attributes that we can use across all element types #} -{%- set commonAttributes %} class="{{ classNames }}" data-module="govuk-button" {%- for attribute, value in (params.attributes.items() if params.attributes else {}.items()) %} {{ attribute }}="{{ value }}"{% endfor %}{% if params.id %} id="{{ params.id }}"{% endif %}{% endset %} +{%- set commonAttributes %} class="{{ classNames }}" data-module="govuk-button" {{- govukAttributes(params.attributes) -}} {% if params.id %} id="{{ params.id }}"{% endif %}{% endset %} {#- Define common attributes we can use for both button and input types #} diff --git a/govuk_frontend_jinja/templates/components/character-count/macro.html b/govuk_frontend_jinja/templates/components/character-count/macro.html index 23e1a8d3..e58f5907 100644 --- a/govuk_frontend_jinja/templates/components/character-count/macro.html +++ b/govuk_frontend_jinja/templates/components/character-count/macro.html @@ -1,14 +1,47 @@ {% macro govukCharacterCount(params) %} +{% from "govuk_frontend_jinja/macros/attributes.html" import govukAttributes %} {% from "govuk_frontend_jinja/macros/i18n.html" import govukI18nAttributes %} {% from "govuk_frontend_jinja/components/textarea/macro.html" import govukTextarea %} {% from "govuk_frontend_jinja/components/hint/macro.html" import govukHint %} +{#- + If the limit is set in JavaScript, we won't be able to interpolate the message + until JavaScript, so we only set a text if the `maxlength` or `maxwords` options + were provided to the macro. +#} {%- set hasNoLimit = (not params.maxwords and not params.maxlength) -%} +{%- set textareaDescriptionLength = params.maxwords or params.maxlength -%} +{%- set textareaDescriptionText = params.textareaDescriptionText or 'You can enter up to %{count} ' ~ ('words' if params.maxwords else 'characters') -%} +{%- set textareaDescriptionTextNoLimit = textareaDescriptionText | replace('%{count}', textareaDescriptionLength) if not hasNoLimit -%} + +{%- set countMessageHtml %} +{{ govukHint({ + 'text': textareaDescriptionTextNoLimit, + 'id': params.id ~ '-info', + 'classes': 'govuk-character-count__message' ~ (' ' ~ params.countMessage.classes if params.countMessage and params.countMessage.classes) +}) | trim }} +{% if params.formGroup and params.formGroup.afterInput %} + {{- params.formGroup.afterInput.html | safe | trim if params.formGroup and params.formGroup.afterInput.html else params.formGroup.afterInput.text }} +{% endif -%} +{% endset -%} + +{%- set attributesHtml %} + {{- govukAttributes({ + "data-module": "govuk-character-count", + "data-maxlength": { + 'value': params.maxlength, + 'optional': true + }, + "data-threshold": { + 'value': params.threshold, + 'optional': true + }, + "data-maxwords": { + 'value': params.maxwords, + 'optional': true + } + }) -}} -
    - {{ govukTextarea({ - 'id': params.id, - 'name': params.name, - 'describedBy': params.id + '-info', - 'rows': params.rows, - 'spellcheck': params.spellcheck, - 'value': params.value, - 'formGroup': params.formGroup, - 'classes': 'govuk-js-character-count' + (' ' + params.classes if params.classes else ''), - 'label': { - 'html': params.label.html, - 'text': params.label.text, - 'classes': params.label.classes, - 'isPageHeading': params.label.isPageHeading, - 'attributes': params.label.attributes, - 'for': params.id - }, - 'hint': params.hint, - 'errorMessage': params.errorMessage, - 'attributes': params.attributes - }) }} + }) -}} +{% endset -%} - {%- set textareaDescriptionLength = params.maxwords or params.maxlength %} - {%- set textareaDescriptionText = params.textareaDescriptionText or 'You can enter up to %{count} ' + ('words' if params.maxwords else 'characters') %} - {#- - If the limit is set in JavaScript, we won't be able to interpolate the message - until JavaScript, so we only set a text if the `maxlength` or `maxwords` options - were provided to the macro. - #} - {{ govukHint({ - 'text': ((textareaDescriptionText) | replace('%{count}', textareaDescriptionLength) if not hasNoLimit), - 'id': params.id + '-info', - 'classes': 'govuk-character-count__message' + (' ' + params.countMessage.classes if params.countMessage and params.countMessage.classes else '') - }) | trim | indent(2) }} -
    +{#- Append form group attributes onto attributes set above #} +{%- if params.formGroup -%} + {%- for name, value in params.formGroup.attributes if params.formGroup %} + {% set attributesHtml = attributesHtml ~ " " ~ name | escape ~ '="' ~ value | escape ~ '"' %} + {% endfor -%} +{%- endif -%} + +{{ govukTextarea({ + 'id': params.id, + 'name': params.name, + 'describedBy': params.id ~ '-info', + 'rows': params.rows, + 'spellcheck': params.spellcheck, + 'value': params.value, + 'formGroup': { + 'classes': 'govuk-character-count' ~ (' ' ~ params.formGroup.classes if params.formGroup and params.formGroup.classes), + 'attributes': attributesHtml, + 'beforeInput': params.formGroup.beforeInput if params.fromGroup, + 'afterInput': { + 'html': countMessageHtml + } + }, + 'classes': 'govuk-js-character-count' ~ (' ' ~ params.classes if params.classes), + 'label': { + 'html': params.label.html, + 'text': params.label.text, + 'classes': params.label.classes, + 'isPageHeading': params.label.isPageHeading, + 'attributes': params.label.attributes, + 'for': params.id + }, + 'hint': params.hint, + 'errorMessage': params.errorMessage, + 'attributes': params.attributes +}) | trim }} {% endmacro %} diff --git a/govuk_frontend_jinja/templates/components/checkboxes/macro.html b/govuk_frontend_jinja/templates/components/checkboxes/macro.html index a45d0dfb..4c257095 100644 --- a/govuk_frontend_jinja/templates/components/checkboxes/macro.html +++ b/govuk_frontend_jinja/templates/components/checkboxes/macro.html @@ -1,4 +1,5 @@ {% macro govukCheckboxes(params) %} +{% from "govuk_frontend_jinja/macros/attributes.html" import govukAttributes %} {% from "govuk_frontend_jinja/components/error-message/macro.html" import govukErrorMessage %} {% from "govuk_frontend_jinja/components/fieldset/macro.html" import govukFieldset %} {% from "govuk_frontend_jinja/components/hint/macro.html" import govukHint %} @@ -20,11 +21,58 @@ {#- fieldset is false by default -#} {% set hasFieldset = true if params.fieldset else false %} +{%- macro _checkboxItem(params, item, index) %} + {#- If the user explicitly sets an id, use this instead of the regular idPrefix -#} + {#- The first id should not have a number suffix so it's easy to link to from the error summary component -#} + {% set itemId = item.id if item.id else idPrefix ~ ("-" ~ index if index > 1 else "") %} + {% set itemName = item.name if item.name else params.name %} + {% set conditionalId = "conditional-" ~ itemId %} + {%- if item.divider %} +
    {{ item.divider }}
    + {% else %} + {% set isChecked = item.checked | default((item.value in params.get('values', []) and item.checked is not false) if params.values else false, true) %} + {% set hasHint = true if item.hint and (item.hint.text or item.hint.html) %} + {% set itemHintId = itemId ~ "-item-hint" if hasHint else "" %} + {% set itemDescribedBy = ns.describedBy if not hasFieldset else "" %} + {% set itemDescribedBy = (itemDescribedBy ~ " " ~ itemHintId) | trim %} +
    + + {{ govukLabel({ + 'html': item.html, + 'text': item.text, + 'classes': 'govuk-checkboxes__label' ~ (' ' ~ item.label.classes if item.label and item.label.classes else ""), + 'attributes': item.label.attributes if item.label, + 'for': itemId + }) | trim | indent(6) }} + {% if hasHint %} + {{ govukHint({ + 'id': itemHintId, + 'classes': 'govuk-checkboxes__hint' ~ (' ' ~ item.hint.classes if item.hint and item.hint.classes else ""), + 'attributes': item.hint.attributes if item.hint, + 'html': item.hint.html, + 'text': item.hint.text + }) | trim | indent(6) }} + {% endif %} +
    + {% if item.conditional and item.conditional.html %} +
    + {{ item.conditional.html | safe | trim }} +
    + {% endif %} + {% endif %} +{% endmacro -%} + {#- Capture the HTML so we can optionally nest it in a fieldset -#} {% set innerHtml %} {% if params.hint %} - {% set hintId = idPrefix + '-hint' %} - {% set ns.describedBy = ns.describedBy + ' ' + hintId if ns.describedBy else hintId %} + {% set hintId = idPrefix ~ '-hint' %} + {% set ns.describedBy = ns.describedBy ~ ' ' ~ hintId if ns.describedBy else hintId %} {{ govukHint({ 'id': hintId, 'classes': params.hint.classes, @@ -34,8 +82,8 @@ }) | trim | indent(2) }} {% endif %} {% if params.errorMessage %} - {% set errorId = idPrefix + '-error' %} - {% set ns.describedBy = ns.describedBy + ' ' + errorId if ns.describedBy else errorId %} + {% set errorId = idPrefix ~ '-error' %} + {% set ns.describedBy = ns.describedBy ~ ' ' ~ errorId if ns.describedBy else errorId %} {{ govukErrorMessage({ 'id': errorId, 'classes': params.errorMessage.classes, @@ -46,67 +94,23 @@ }) | trim | indent(2) }} {% endif %}
    + {{- govukAttributes(params.attributes) }} data-module="govuk-checkboxes"> + {% if params.formGroup and params.formGroup.beforeInputs %} + {{ params.formGroup.beforeInputs.html | safe | trim | indent(4) if params.formGroup and params.formGroup.beforeInputs.html else params.formGroup.beforeInputs.text }} + {% endif %} {% for item in params['items'] %} {% if item %} - {#- If the user explicitly sets an id, use this instead of the regular idPrefix -#} - {%- if item.id -%} - {%- set id = item.id -%} - {%- else -%} - {#- The first id should not have a number suffix so it's easy to link to from the error summary component -#} - {%- if loop.first -%} - {%- set id = idPrefix %} - {% else %} - {%- set id = idPrefix + "-" ~ loop.index -%} - {%- endif -%} - {%- endif -%} - {% set name = item.name if item.name else params.name %} - {% set conditionalId = "conditional-" + id %} - {%- if item.divider %} -
    {{ item.divider }}
    - {%- else %} - {% set isChecked = item.checked | default((item.value in params.get('values', []) and item.checked != false) if params.values else false, true) %} - {% set hasHint = true if item.hint and (item.hint.text or item.hint.html) %} - {% set itemHintId = id + "-item-hint" if hasHint else "" %} - {% set itemDescribedBy = ns.describedBy if not hasFieldset else "" %} - {% set itemDescribedBy = (itemDescribedBy + " " + itemHintId) | trim %} -
    - - {{ govukLabel({ - 'html': item.html, - 'text': item.text, - 'classes': 'govuk-checkboxes__label' + (' ' + item.label.classes if item.label and item.label.classes else ''), - 'attributes': item.label.attributes if item.label, - 'for': id - }) | trim | indent(6) }} - {% if hasHint %} - {{ govukHint({ - 'id': itemHintId, - 'classes': 'govuk-checkboxes__hint' + (' ' + item.hint.classes if item.hint.classes else ''), - 'attributes': item.hint.attributes, - 'html': item.hint.html, - 'text': item.hint.text - }) | trim | indent(6) }} - {% endif %} -
    - {% if item.conditional and item.conditional.html %} -
    - {{ item.conditional.html | safe }} -
    - {% endif %} - {% endif %} + {{- _checkboxItem(params, item, loop.index) -}} {% endif %} {% endfor %} + {% if params.formGroup and params.formGroup.afterInputs %} + {{ params.formGroup.afterInputs.html | safe | trim | indent(4) if params.formGroup and params.formGroup.afterInputs.html else params.formGroup.afterInputs.text }} + {% endif %}
    {% endset -%} -
    +
    {% if hasFieldset %} {{ govukFieldset({ 'describedBy': ns.describedBy, diff --git a/govuk_frontend_jinja/templates/components/cookie-banner/macro.html b/govuk_frontend_jinja/templates/components/cookie-banner/macro.html index 18f67e6a..7bde52d2 100644 --- a/govuk_frontend_jinja/templates/components/cookie-banner/macro.html +++ b/govuk_frontend_jinja/templates/components/cookie-banner/macro.html @@ -1,66 +1,59 @@ {% macro govukCookieBanner (params) %} +{% from "govuk_frontend_jinja/macros/attributes.html" import govukAttributes %} {% from "govuk_frontend_jinja/components/button/macro.html" import govukButton -%}