diff --git a/app/__init__.py b/app/__init__.py index e7e19259c..f6c91c3a1 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -575,7 +575,6 @@ def init_jinja(application): repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) template_folders = [ os.path.join(repo_root, 'app/templates'), - os.path.join(repo_root, 'app/templates/vendor/govuk-frontend'), ] jinja_loader = jinja2.FileSystemLoader(template_folders) application.jinja_loader = jinja_loader diff --git a/app/main/forms.py b/app/main/forms.py index cdceab1ed..43783cd23 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -258,7 +258,7 @@ def govuk_text_input_field_widget(self, field, type=None, param_extensions=None, merge_jsonlike(params, param_extensions) return Markup( - render_template('vendor/govuk-frontend/components/input/template.njk', params=params)) + render_template('components/uk_components/input/template.njk', params=params)) class GovukTextInputField(StringField): @@ -793,7 +793,7 @@ def govuk_radios_field_widget(self, field, param_extensions=None, **kwargs): merge_jsonlike(params, param_extensions) return Markup( - render_template('components/radios/template.njk', params=params)) + render_template('components/uk_components/radios/template.njk', params=params)) class GovukCheckboxField(BooleanField): @@ -850,7 +850,7 @@ class GovukTextareaField(TextAreaField): merge_jsonlike(params, param_extensions) return Markup( - render_template('components/textarea/template.njk', params=params)) + render_template('components/uk_components/textarea/template.njk', params=params)) # based on work done by @richardjpope: https://github.com/richardjpope/recourse/blob/master/recourse/forms.py#L6 diff --git a/app/templates/admin_template.html b/app/templates/admin_template.html index 09e4c9262..9ad821632 100644 --- a/app/templates/admin_template.html +++ b/app/templates/admin_template.html @@ -2,15 +2,6 @@ {% from "components/banner.html" import banner %} {% from "components/cookie-banner.html" import cookie_banner %} -{% block headIcons %} - - {# Hardcoded value of $govuk-black #} - - - - -{% endblock %} - {% block head %} {%- for font in font_paths %} @@ -47,6 +38,7 @@ {% endblock %} {% block header %} + {% endblock %} {% block footer %} diff --git a/app/templates/components/banner.html b/app/templates/components/banner.html index 109ff3023..764adbd48 100644 --- a/app/templates/components/banner.html +++ b/app/templates/components/banner.html @@ -1,5 +1,5 @@ {% from "components/form.html" import form_wrapper %} -{% from "components/button/macro.njk" import govukButton %} +{% from "components/uk_components/button/macro.njk" import govukButton %} {% macro banner(body, type=None, with_tick=False, delete_button=None, subhead=None, context=None, action=None, id=None, thing=None) %}
{{ (params.html | safe if params.html else (params.text if params.text else 'Back')) }} diff --git a/app/templates/components/uk_components/button/README.md b/app/templates/components/uk_components/button/README.md new file mode 100644 index 000000000..45425bc11 --- /dev/null +++ b/app/templates/components/uk_components/button/README.md @@ -0,0 +1,15 @@ +# Button + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the button component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/button). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/button/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/button/_button.scss b/app/templates/components/uk_components/button/_button.scss new file mode 100644 index 000000000..a39a62e29 --- /dev/null +++ b/app/templates/components/uk_components/button/_button.scss @@ -0,0 +1,256 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@include govuk-exports("govuk/component/button") { + // Primary button variables + $govuk-button-colour: #00823b; // sass-lint:disable no-color-literals + $govuk-button-hover-colour: govuk-shade($govuk-button-colour, 20%); + $govuk-button-shadow-colour: govuk-shade($govuk-button-colour, 60%); + $govuk-button-text-colour: govuk-colour("white"); + + // Secondary button variables + $govuk-secondary-button-colour: govuk-colour("grey-3"); + $govuk-secondary-button-hover-colour: govuk-shade($govuk-secondary-button-colour, 10%); + $govuk-secondary-button-shadow-colour: govuk-shade($govuk-secondary-button-colour, 40%); + $govuk-secondary-button-text-colour: govuk-colour("black"); + + // Warning button variables + $govuk-warning-button-colour: govuk-colour("red"); + $govuk-warning-button-hover-colour: govuk-shade($govuk-warning-button-colour, 20%); + $govuk-warning-button-shadow-colour: govuk-shade($govuk-warning-button-colour, 60%); + $govuk-warning-button-text-colour: govuk-colour("white"); + + // Because the shadow (s0) is visually 'part of' the button, we need to reduce + // the height of the button to compensate by adjusting its padding (s1) and + // increase the bottom margin to include it (s2). + $button-shadow-size: $govuk-border-width-form-element; + + .govuk-button { + @include govuk-font($size: 19, $line-height: 19px); + @include govuk-focusable; + + box-sizing: border-box; + display: inline-block; + position: relative; + width: 100%; + margin-top: 0; + @include govuk-responsive-margin(6, "bottom", $adjustment: $button-shadow-size); // s2 + padding: (govuk-spacing(2) - $govuk-border-width-form-element - ($button-shadow-size / 2)) govuk-spacing(2); // s1 + border: $govuk-border-width-form-element solid transparent; + border-radius: 0; + color: $govuk-button-text-colour; + background-color: $govuk-button-colour; + box-shadow: 0 $button-shadow-size 0 $govuk-button-shadow-colour; // s0 + text-align: center; + vertical-align: top; + cursor: pointer; + -webkit-appearance: none; + + @include govuk-if-ie8 { + border-bottom: $button-shadow-size solid $govuk-button-shadow-colour; + } + + @include govuk-media-query($from: tablet) { + width: auto; + } + + // Ensure that any global link styles are overridden + &:link, + &:visited, + &:active, + &:hover { + color: $govuk-button-text-colour; + text-decoration: none; + } + + // alphagov/govuk_template includes a specific a:link:focus selector + // designed to make unvisited links a slightly darker blue when focussed, so + // we need to override the text colour for that combination of selectors so + // so that unvisited links styled as buttons do not end up with dark blue + // text when focussed. + @include govuk-compatibility(govuk_template) { + &:link:focus { + color: $govuk-button-text-colour; + } + } + + // Fix unwanted button padding in Firefox + &::-moz-focus-inner { + padding: 0; + border: 0; + } + + &:hover, + &:focus { + background-color: $govuk-button-hover-colour; + } + + &:active { + top: $button-shadow-size; + box-shadow: none; + + @include govuk-if-ie8 { + border-bottom-width: 0; + } + } + + // The following adjustments do not work for as + // non-container elements cannot include pseudo elements (i.e. ::before). + + // Use a pseudo element to expand the click target area to include the + // button's shadow as well, in case users try to click it. + &::before { + content: ""; + display: block; + + position: absolute; + + top: -$govuk-border-width-form-element; + right: -$govuk-border-width-form-element; + bottom: -($govuk-border-width-form-element + $button-shadow-size); + left: -$govuk-border-width-form-element; + + background: transparent; + } + + // When the button is active it is shifted down by $button-shadow-size to + // denote a 'pressed' state. If the user happened to click at the very top + // of the button, their mouse is no longer over the button (because it has + // 'moved beneath them') and so the click event is not fired. + // + // This corrects that by shifting the top of the pseudo element so that it + // continues to cover the area that the user originally clicked, which means + // the click event is still fired. + // + // πŸŽ‰ + &:active::before { + top: -($govuk-border-width-form-element + $button-shadow-size); + } + } + + .govuk-button--disabled, + .govuk-button[disabled="disabled"], + .govuk-button[disabled] { + opacity: (.5); + + &:hover { + background-color: $govuk-button-colour; + cursor: default; + } + + &:focus { + outline: none; + } + + &:active { + top: 0; + box-shadow: 0 $button-shadow-size 0 $govuk-button-shadow-colour; // s0 + @include govuk-if-ie8 { + border-bottom: $button-shadow-size solid $govuk-button-shadow-colour; // s0 + } + } + } + + .govuk-button--secondary { + background-color: $govuk-secondary-button-colour; + box-shadow: 0 $button-shadow-size 0 $govuk-secondary-button-shadow-colour; + + &, + &:link, + &:visited, + &:active, + &:hover { + color: $govuk-secondary-button-text-colour; + } + + // alphagov/govuk_template includes a specific a:link:focus selector + // designed to make unvisited links a slightly darker blue when focussed, so + // we need to override the text colour for that combination of selectors so + // so that unvisited links styled as buttons do not end up with dark blue + // text when focussed. + @include govuk-compatibility(govuk_template) { + &:link:focus { + color: $govuk-secondary-button-text-colour; + } + } + + &:hover, + &:focus { + background-color: $govuk-secondary-button-hover-colour; + + &[disabled] { + background-color: $govuk-secondary-button-colour; + } + } + } + + .govuk-button--warning { + background-color: $govuk-warning-button-colour; + box-shadow: 0 $button-shadow-size 0 $govuk-warning-button-shadow-colour; + + &, + &:link, + &:visited, + &:active, + &:hover { + color: $govuk-warning-button-text-colour; + } + + // alphagov/govuk_template includes a specific a:link:focus selector + // designed to make unvisited links a slightly darker blue when focussed, so + // we need to override the text colour for that combination of selectors so + // so that unvisited links styled as buttons do not end up with dark blue + // text when focussed. + @include govuk-compatibility(govuk_template) { + &:link:focus { + color: $govuk-warning-button-text-colour; + } + } + + &:hover, + &:focus { + background-color: $govuk-warning-button-hover-colour; + + &[disabled] { + background-color: $govuk-warning-button-colour; + } + } + } + + .govuk-button--start { + @include govuk-typography-weight-bold; + @include govuk-typography-responsive($size: 24, $override-line-height: 1); + + min-height: auto; + padding-top: govuk-spacing(2) - $govuk-border-width-form-element; + padding-right: govuk-spacing(7); + padding-bottom: govuk-spacing(2) - $govuk-border-width-form-element; + padding-left: govuk-spacing(3); + + background-image: govuk-image-url("icon-pointer.png"); + background-repeat: no-repeat; + background-position: 100% 50%; + + @include govuk-device-pixel-ratio { + background-image: govuk-image-url("icon-pointer-2x.png"); + background-size: 30px 19px; + } + } + + // Begin adjustments for font baseline offset + // These should be removed when the font is updated with the correct baseline + // For the 1px addition please see https://github.com/alphagov/govuk-frontend/pull/365#discussion_r154349428 + + $offset: 2; + + .govuk-button { + padding-top: (govuk-spacing(2) - $govuk-border-width-form-element - ($button-shadow-size / 2) + $offset); // s1 + padding-bottom: (govuk-spacing(2) - $govuk-border-width-form-element - ($button-shadow-size / 2) - $offset + 1); // s1 + } + + .govuk-button--start { + padding-top: (govuk-spacing(2) - $govuk-border-width-form-element - ($button-shadow-size / 2) + $offset); // s1 + padding-bottom: (govuk-spacing(2) - $govuk-border-width-form-element - ($button-shadow-size / 2) - $offset + 1); // s1 + } +} diff --git a/app/templates/components/uk_components/button/macro-options.json b/app/templates/components/uk_components/button/macro-options.json new file mode 100644 index 000000000..1e9b76c27 --- /dev/null +++ b/app/templates/components/uk_components/button/macro-options.json @@ -0,0 +1,68 @@ +[ + { + "name": "element", + "type": "string", + "required": false, + "description": "Whether to use an `input`, `button` or `a` element to create the button. In most cases you will not need to set this as it will be configured automatically if you use `href` or `html`." + }, + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text for the button or link. If `html` is provided, the `text` argument will be ignored and `element` will be automatically set to `button` unless `href` is also set, or it has already been defined. This argument has no effect if `element` is set to `input`." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML for the button or link. If `html` is provided, the `text` argument will be ignored and `element` will be automatically set to `button` unless `href` is also set, or it has already been defined. This argument has no effect if `element` is set to `input`." + }, + { + "name": "name", + "type": "string", + "required": true, + "description": "Name for the `input` or `button`. This has no effect on `a` elements." + }, + { + "name": "type", + "type": "string", + "required": true, + "description": "Type of `input` or `button` – `button`, `submit` or `reset`. Defaults to `submit`. This has no effect on `a` elements." + }, + { + "name": "value", + "type": "string", + "required": true, + "description": "Value for the `button` tag. This has no effect on `a` or `input` elements." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "description": "Whether the button should be disabled. For button and input elements, `disabled` and `aria-disabled` attributes will be set automatically." + }, + { + "name": "href", + "type": "string", + "required": false, + "description": "The URL that the button should link to. If this is set, `element` will be automatically set to `a` if it has not already been defined." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the button component." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the button component." + }, + { + "name": "preventDoubleClick", + "type": "boolean", + "required": false, + "description": "Prevent accidental double clicks on submit buttons from submitting forms multiple times" + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/button/macro.njk b/app/templates/components/uk_components/button/macro.njk new file mode 100644 index 000000000..352d538c5 --- /dev/null +++ b/app/templates/components/uk_components/button/macro.njk @@ -0,0 +1,3 @@ +{% macro govukButton(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/button/template.njk b/app/templates/components/uk_components/button/template.njk new file mode 100644 index 000000000..393112675 --- /dev/null +++ b/app/templates/components/uk_components/button/template.njk @@ -0,0 +1,35 @@ +{# Determine type of element to use, if not explicitly set -#} + +{% if params.element %} + {% set element = params.element | lower %} +{% else %} + {% if params.href %} + {% set element = 'a' %} + {% else %} + {% set element = 'button' %} + {% endif %} +{% endif %} + +{#- Define common attributes that we can use across all element types #} + +{%- set commonAttributes %} class="govuk-button{% if params.classes %} {{ params.classes }}{% endif %}{% if params.disabled %} govuk-button--disabled{% endif %}"{% for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %}{% endset %} + +{#- Define common attributes we can use for both button and input types #} + +{%- set buttonAttributes %}{% if params.name %} name="{{ params.name }}"{% endif %} type="{{ params.type if params.type else 'submit' }}"{% if params.disabled %} disabled="disabled" aria-disabled="true"{% endif %}{% if params.preventDoubleClick %} data-prevent-double-click="true"{% endif %}{% endset %} + +{#- Actually create a button... or a link! #} + +{%- if element == 'a' %} + + {{ params.html | safe if params.html else params.text }} + + +{%- elseif element == 'button' %} + + +{%- elseif element == 'input' %} + +{%- endif %} diff --git a/app/templates/components/uk_components/checkboxes/README.md b/app/templates/components/uk_components/checkboxes/README.md new file mode 100644 index 000000000..8f094fa21 --- /dev/null +++ b/app/templates/components/uk_components/checkboxes/README.md @@ -0,0 +1,15 @@ +# Checkboxes + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the checkboxes component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/checkboxes). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/checkboxes/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/checkboxes/_checkboxes.scss b/app/templates/components/uk_components/checkboxes/_checkboxes.scss new file mode 100644 index 000000000..86309549f --- /dev/null +++ b/app/templates/components/uk_components/checkboxes/_checkboxes.scss @@ -0,0 +1,310 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@import "../error-message/error-message"; +@import "../fieldset/fieldset"; +@import "../hint/hint"; +@import "../label/label"; + +@include govuk-exports("govuk/component/checkboxes") { + + $govuk-touch-target-size: 44px; + $govuk-checkboxes-size: 40px; + $govuk-small-checkboxes-size: 24px; + $govuk-checkboxes-label-padding-left-right: govuk-spacing(3); + + .govuk-checkboxes__item { + @include govuk-font($size: 19); + + display: block; + position: relative; + + min-height: $govuk-checkboxes-size; + + margin-bottom: govuk-spacing(2); + padding-left: $govuk-checkboxes-size; + + clear: left; + } + + .govuk-checkboxes__item:last-child, + .govuk-checkboxes__item:last-of-type { + margin-bottom: 0; + } + + .govuk-checkboxes__input { + $input-offset: ($govuk-touch-target-size - $govuk-checkboxes-size) / 2; + + cursor: pointer; + + // IE8 doesn’t support pseudo-elements, so we don’t want to hide native + // elements there. + @include govuk-not-ie8 { + position: absolute; + + z-index: 1; + top: $input-offset * -1; + left: $input-offset * -1; + + width: $govuk-touch-target-size; + height: $govuk-touch-target-size; + margin: 0; + + opacity: 0; + } + + @include govuk-if-ie8 { + margin-top: 10px; + margin-right: $govuk-checkboxes-size / -2; + margin-left: $govuk-checkboxes-size / -2; + float: left; + + // add focus outline to input + &:focus { + outline: $govuk-focus-width solid $govuk-focus-colour; + } + } + } + + .govuk-checkboxes__label { + display: inline-block; + margin-bottom: 0; + padding: 8px $govuk-checkboxes-label-padding-left-right govuk-spacing(1); + cursor: pointer; + // remove 300ms pause on mobile + -ms-touch-action: manipulation; + touch-action: manipulation; + } + + // [ ] Check box + .govuk-checkboxes__label::before { + content: ""; + box-sizing: border-box; + position: absolute; + top: 0; + left: 0; + width: $govuk-checkboxes-size; + height: $govuk-checkboxes-size; + border: $govuk-border-width-form-element solid currentColor; + background: transparent; + } + + // βœ” Check mark + // + // The check mark is a box with a border on the left and bottom side (└──), + // rotated 45 degrees + .govuk-checkboxes__label::after { + content: ""; + + position: absolute; + top: 11px; + left: 9px; + width: 18px; + height: 7px; + + -webkit-transform: rotate(-45deg); + + -ms-transform: rotate(-45deg); + + transform: rotate(-45deg); + border: solid; + border-width: 0 0 $govuk-border-width $govuk-border-width; + // Fix bug in IE11 caused by transform rotate (-45deg). + // See: alphagov/govuk_elements/issues/518 + border-top-color: transparent; + + opacity: 0; + + background: transparent; + } + + .govuk-checkboxes__hint { + display: block; + padding-right: $govuk-checkboxes-label-padding-left-right; + padding-left: $govuk-checkboxes-label-padding-left-right; + } + + // Focused state + .govuk-checkboxes__input:focus + .govuk-checkboxes__label::before { + // Since box-shadows are removed when users customise their colours, we set + // a transparent outline that is shown instead. + // https://accessibility.blog.gov.uk/2017/03/27/how-users-change-colours-on-websites/ + outline: $govuk-focus-width solid transparent; + outline-offset: $govuk-focus-width; + box-shadow: 0 0 0 $govuk-focus-width $govuk-focus-colour; + } + + // Selected state + .govuk-checkboxes__input:checked + .govuk-checkboxes__label::after { + opacity: 1; + } + + // Disabled state + .govuk-checkboxes__input:disabled, + .govuk-checkboxes__input:disabled + .govuk-checkboxes__label { + cursor: default; + } + + .govuk-checkboxes__input:disabled + .govuk-checkboxes__label { + opacity: .5; + } + + // ========================================================= + // Conditional reveals + // ========================================================= + + $conditional-border-width: $govuk-border-width-mobile; + // Calculate the amount of padding needed to keep the border centered against the checkbox. + $conditional-border-padding: ($govuk-checkboxes-size / 2) - ($conditional-border-width / 2); + // Move the border centered with the checkbox + $conditional-margin-left: $conditional-border-padding; + // Move the contents of the conditional inline with the label + $conditional-padding-left: $conditional-border-padding + $govuk-checkboxes-label-padding-left-right; + + .govuk-checkboxes__conditional { + @include govuk-responsive-margin(4, "bottom"); + margin-left: $conditional-margin-left; + padding-left: $conditional-padding-left; + border-left: $conditional-border-width solid $govuk-border-colour; + + .js-enabled &--hidden { + display: none; + } + + & > :last-child { + margin-bottom: 0; + } + } + + // ========================================================= + // Small checkboxes + // ========================================================= + + .govuk-checkboxes--small { + + $input-offset: ($govuk-touch-target-size - $govuk-small-checkboxes-size) / 2; + $label-offset: $govuk-touch-target-size - $input-offset; + + .govuk-checkboxes__item { + @include govuk-clearfix; + min-height: 0; + margin-bottom: 0; + padding-left: $label-offset; + float: left; + } + + // Shift the touch target into the left margin so that the visible edge of + // the control is aligned + // + // ┆What colours do you like? + // β”Œβ”†β”€β”€β”€β” + // │┆[] β”‚ Purple + // β””β”†β–²β”€β”€β”˜ + // ▲┆└─ Check box pseudo element, aligned with margin + // └─── Touch target (invisible input), shifted into the margin + .govuk-checkboxes__input { + @include govuk-not-ie8 { + left: $input-offset * -1; + } + + @include govuk-if-ie8 { + margin-left: $govuk-small-checkboxes-size * -1; + } + } + + // Adjust the size and position of the label. + // + // Unlike larger checkboxes, we also have to float the label in order to + // 'shrink' it, preventing the hover state from kicking in across the full + // width of the parent element. + .govuk-checkboxes__label { + margin-top: -2px; + padding: 13px govuk-spacing(3) 13px 1px; + float: left; + + @include govuk-media-query($from: tablet) { + padding: 11px govuk-spacing(3) 10px 1px; + } + } + + // [ ] Check box + // + // Reduce the size of the check box [1], vertically center it within the + // touch target [2] + .govuk-checkboxes__label::before { + top: $input-offset - $govuk-border-width-form-element; // 2 + width: $govuk-small-checkboxes-size; // 1 + height: $govuk-small-checkboxes-size; // 1 + } + + // βœ” Check mark + // + // Reduce the size of the check mark and re-align within the checkbox + .govuk-checkboxes__label::after { + top: 15px; + left: 6px; + width: 9px; + height: 3.5px; + border-width: 0 0 3px 3px; + } + + // Fix position of hint with small checkboxes + // + // Do not use hints with small checkboxes – because they're within the input + // wrapper they trigger the hover state, but clicking them doesn't actually + // activate the control. + // + // (If you do use them, they won't look completely broken... but seriously, + // don't use them) + .govuk-checkboxes__hint { + padding: 0; + clear: both; + } + + // Align conditional reveals with small checkboxes + .govuk-checkboxes__conditional { + $margin-left: ($govuk-small-checkboxes-size / 2) - ($conditional-border-width / 2); + margin-left: $margin-left; + padding-left: $label-offset - ($margin-left + $conditional-border-width); + clear: both; + } + + // Hover state for small checkboxes. + // + // We use a hover state for small checkboxes because the touch target size + // is so much larger than their visible size, and so we need to provide + // feedback to the user as to which checkbox they will select when their + // cursor is outside of the visible area. + .govuk-checkboxes__item:hover .govuk-checkboxes__input:not(:disabled) + .govuk-checkboxes__label::before { + box-shadow: 0 0 0 $govuk-hover-width $govuk-hover-colour; + } + + // Because we've overridden the border-shadow provided by the focus state, + // we need to redefine that too. + // + // We use two box shadows, one that restores the original focus state [1] + // and another that then applies the hover state [2]. + .govuk-checkboxes__item:hover .govuk-checkboxes__input:focus + .govuk-checkboxes__label::before { + // sass-lint:disable indentation + box-shadow: 0 0 0 $govuk-focus-width $govuk-focus-colour, // 1 + 0 0 0 $govuk-hover-width $govuk-hover-colour; // 2 + } + + // For devices that explicitly don't support hover, don't provide a hover + // state (e.g. on touch devices like iOS). + // + // We can't use `@media (hover: hover)` because we wouldn't get the hover + // state in browsers that don't support `@media (hover)` (like Internet + // Explorer) – so we have to 'undo' the hover state instead. + @media (hover: none), (pointer: coarse) { + .govuk-checkboxes__item:hover .govuk-checkboxes__input:not(:disabled) + .govuk-checkboxes__label::before { + box-shadow: initial; + } + + .govuk-checkboxes__item:hover .govuk-checkboxes__input:focus + .govuk-checkboxes__label::before { + box-shadow: 0 0 0 $govuk-focus-width $govuk-focus-colour; + } + } + } +} diff --git a/app/templates/components/uk_components/checkboxes/macro-options.json b/app/templates/components/uk_components/checkboxes/macro-options.json new file mode 100644 index 000000000..db2970c10 --- /dev/null +++ b/app/templates/components/uk_components/checkboxes/macro-options.json @@ -0,0 +1,149 @@ +[ + { + "name": "describedBy", + "type": "string", + "required": false, + "description": "One or more element IDs to add to the input `aria-describedby` attribute without a fieldset, used to provide additional descriptive information for screenreader users." + }, + { + "name": "fieldset", + "type": "object", + "required": false, + "description": "Options for the fieldset component (e.g. legend).", + "isComponent": true + }, + { + "name": "hint", + "type": "object", + "required": false, + "description": "Options for the hint component (e.g. text).", + "isComponent": true + }, + { + "name": "errorMessage", + "type": "object", + "required": false, + "description": "Options for the errorMessage component (e.g. text).", + "isComponent": true + }, + { + "name": "formGroup", + "type": "object", + "required": false, + "description": "Options for the form-group wrapper", + "params": [ + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the form group (e.g. to show error state for the whole group)" + } + ] + }, + { + "name": "idPrefix", + "type": "string", + "required": false, + "description": "String to prefix id for each checkbox item if no id is specified on each item. If not passed, fall back to using the name option instead." + }, + { + "name": "name", + "type": "string", + "required": true, + "description": "Name attribute for all checkbox items." + }, + { + "name": "items", + "type": "array", + "required": true, + "description": "Array of checkbox items objects.", + "params": [ + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within each checkbox item label. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within each checkbox item label. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "id", + "type": "string", + "required": false, + "description": "Specific id attribute for the checkbox item. If omitted, then idPrefix option will be applied." + }, + { + "name": "name", + "type": "string", + "required": true, + "description": "Specific name for the checkbox item. If omitted, then component global `name` string will be applied." + }, + { + "name": "value", + "type": "string", + "required": true, + "description": "Value for the checkbox input." + }, + { + "name": "label", + "type": "object", + "required": false, + "description": "Provide attributes and classes to each checkbox item label.", + "isComponent": true + }, + { + "name": "hint", + "type": "object", + "required": false, + "description": "Provide hint to each checkbox item.", + "isComponent": true + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "description": "If true, checkbox will be checked." + }, + { + "name": "conditional", + "type": "boolean", + "required": false, + "description": "If true, content provided will be revealed when the item is checked." + }, + { + "name": "conditional.html", + "type": "string", + "required": false, + "description": "Provide content for the conditional reveal." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "description": "If true, checkbox will be disabled." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the checkbox input tag." + } + ] + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the checkboxes container." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the anchor tag." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/checkboxes/macro.njk b/app/templates/components/uk_components/checkboxes/macro.njk new file mode 100644 index 000000000..e023534a4 --- /dev/null +++ b/app/templates/components/uk_components/checkboxes/macro.njk @@ -0,0 +1,3 @@ +{% macro govukCheckboxes(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/checkboxes/template.njk b/app/templates/components/uk_components/checkboxes/template.njk new file mode 100644 index 000000000..9a12be65c --- /dev/null +++ b/app/templates/components/uk_components/checkboxes/template.njk @@ -0,0 +1,109 @@ +{% from "../error-message/macro.njk" import govukErrorMessage -%} +{% from "../fieldset/macro.njk" import govukFieldset %} +{% from "../hint/macro.njk" import govukHint %} +{% from "../label/macro.njk" import govukLabel %} + +{#- If an id 'prefix' is not passed, fall back to using the name attribute + instead. We need this for error messages and hints as well -#} +{% set idPrefix = params.idPrefix if params.idPrefix else params.name %} + +{#- a record of other elements that we need to associate with the input using + aria-describedby – for example hints or error messages -#} +{% set describedBy = params.describedBy if params.describedBy else "" %} +{% if params.fieldset.describedBy %} + {% set describedBy = params.fieldset.describedBy %} +{% endif %} + +{% set isConditional = false %} +{% for item in params.items %} + {% if item.conditional %} + {% set isConditional = true %} + {% endif %} +{% endfor %} + +{#- fieldset is false by default -#} +{% set hasFieldset = true if params.fieldset else false %} + +{#- Capture the HTML so we can optionally nest it in a fieldset -#} +{% set innerHtml %} +{% if params.hint %} + {% set hintId = idPrefix + '-hint' %} + {% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %} + {{ govukHint({ + id: hintId, + classes: params.hint.classes, + attributes: params.hint.attributes, + html: params.hint.html, + text: params.hint.text + }) | indent(2) | trim }} +{% endif %} +{% if params.errorMessage %} + {% set errorId = idPrefix + '-error' %} + {% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %} + {{ govukErrorMessage({ + id: errorId, + classes: params.errorMessage.classes, + attributes: params.errorMessage.attributes, + html: params.errorMessage.html, + text: params.errorMessage.text, + visuallyHiddenText: params.errorMessage.visuallyHiddenText + }) | indent(2) | trim }} +{% endif %} +
+ {% for item in params.items %} + {% set id = item.id if item.id else idPrefix + "-" + loop.index %} + {% set name = item.name if item.name else params.name %} + {% set conditionalId = "conditional-" + id %} + {% set hasHint = true if item.hint.text or item.hint.html %} + {% set itemHintId = id + "-item-hint" if hasHint else "" %} + {% set itemDescribedBy = 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.classes), + attributes: item.label.attributes, + for: id + }) | indent(6) | trim }} + {%- if hasHint %} + {{ govukHint({ + id: itemHintId, + classes: 'govuk-checkboxes__hint', + attributes: item.hint.attributes, + html: item.hint.html, + text: item.hint.text + }) | indent(6) | trim }} + {%- endif %} +
+ {% if item.conditional %} +
+ {{ item.conditional.html | safe }} +
+ {% endif %} + {% endfor %} +
+{% endset -%} + +
+{% if params.fieldset %} + {% call govukFieldset({ + describedBy: describedBy, + classes: params.fieldset.classes, + attributes: params.fieldset.attributes, + legend: params.fieldset.legend + }) %} + {{ innerHtml | trim | safe }} + {% endcall %} +{% else %} + {{ innerHtml | trim | safe }} +{% endif %} +
diff --git a/app/templates/components/uk_components/details/README.md b/app/templates/components/uk_components/details/README.md new file mode 100644 index 000000000..c44486c73 --- /dev/null +++ b/app/templates/components/uk_components/details/README.md @@ -0,0 +1,15 @@ +# Details + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the details component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/details). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/details/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/details/_details.scss b/app/templates/components/uk_components/details/_details.scss new file mode 100644 index 000000000..44c80ad58 --- /dev/null +++ b/app/templates/components/uk_components/details/_details.scss @@ -0,0 +1,89 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@include govuk-exports("govuk/component/details") { + + .govuk-details { + @include govuk-font($size: 19); + @include govuk-text-colour; + @include govuk-responsive-margin(6, "bottom"); + + display: block; + } + + .govuk-details__summary { + // Make the focus outline shrink-wrap the text content of the summary + display: inline-block; + + // Absolutely position the marker against this element + position: relative; + + margin-bottom: govuk-spacing(1); + + // Allow for absolutely positioned marker and align with disclosed text + padding-left: govuk-spacing(4) + $govuk-border-width; + + // Style the summary to look like a link... + color: $govuk-link-colour; + cursor: pointer; + } + + // ...but only underline the text, not the arrow + .govuk-details__summary-text { + text-decoration: underline; + } + + .govuk-details__summary:hover { + color: $govuk-link-hover-colour; + } + + .govuk-details__summary:focus { + // -1px offset fixes gap between background and outline in Firefox + outline: ($govuk-focus-width + 1px) solid $govuk-focus-colour; + outline-offset: -1px; + // When focussed, the text colour needs to be darker to ensure that colour + // contrast is still acceptable + color: $govuk-focus-text-colour; + background: $govuk-focus-colour; + } + + // Remove the default details marker so we can style our own consistently and + // ensure it displays in Firefox (see implementation.md for details) + .govuk-details__summary::-webkit-details-marker { + display: none; + } + + // Append our own open / closed marker using a pseudo-element + .govuk-details__summary:before { + content: ""; + position: absolute; + + top: 0; + bottom: 0; + left: 0; + + margin: auto; + + @include govuk-shape-arrow($direction: right, $base: 14px); + + .govuk-details[open] > & { + @include govuk-shape-arrow($direction: down, $base: 14px); + } + } + + .govuk-details__text { + padding: govuk-spacing(3); + padding-left: govuk-spacing(4); + border-left: $govuk-border-width solid $govuk-border-colour; + } + + .govuk-details__text p { + margin-top: 0; + margin-bottom: govuk-spacing(4); + } + + .govuk-details__text > :last-child { + margin-bottom: 0; + } +} diff --git a/app/templates/components/uk_components/details/macro-options.json b/app/templates/components/uk_components/details/macro-options.json new file mode 100644 index 000000000..8ad052b6d --- /dev/null +++ b/app/templates/components/uk_components/details/macro-options.json @@ -0,0 +1,50 @@ +[ + { + "name": "summaryText", + "type": "string", + "required": true, + "description": "If `summmaryHtml` is set, this is not required. Text to use within the summary element (the visible part of the details element). If `summaryHtml` is provided, the `summaryText` argument will be ignored." + }, + { + "name": "summaryHtml", + "type": "string", + "required": true, + "description": "If `summmaryText` is set, this is not required. HTML to use within the summary element (the visible part of the details element). If `summaryHtml` is provided, the `summaryText` argument will be ignored." + }, + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within the disclosed part of the details element. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within the disclosed part of the details element. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "id", + "type": "string", + "required": false, + "description": "Id to add to the details element." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "description": "If true, details element will be expanded." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the `
` element." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the `
` element." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/details/macro.njk b/app/templates/components/uk_components/details/macro.njk new file mode 100644 index 000000000..e53969983 --- /dev/null +++ b/app/templates/components/uk_components/details/macro.njk @@ -0,0 +1,3 @@ +{% macro govukDetails(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/details/template.njk b/app/templates/components/uk_components/details/template.njk new file mode 100644 index 000000000..999a7ec0d --- /dev/null +++ b/app/templates/components/uk_components/details/template.njk @@ -0,0 +1,10 @@ +
+ + + {{ params.summaryHtml | safe if params.summaryHtml else params.summaryText }} + + +
+ {{ params.html | safe if params.html else params.text }} +
+
diff --git a/app/templates/components/uk_components/error-message/README.md b/app/templates/components/uk_components/error-message/README.md new file mode 100644 index 000000000..909791bda --- /dev/null +++ b/app/templates/components/uk_components/error-message/README.md @@ -0,0 +1,15 @@ +# Error message + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the error message component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/error-message). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/error-message/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/error-message/_error-message.scss b/app/templates/components/uk_components/error-message/_error-message.scss new file mode 100644 index 000000000..b97298c3a --- /dev/null +++ b/app/templates/components/uk_components/error-message/_error-message.scss @@ -0,0 +1,15 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@include govuk-exports("govuk/component/error-message") { + .govuk-error-message { + @include govuk-font($size: 19, $weight: bold); + + display: block; + margin-bottom: govuk-spacing(3); + clear: both; + + color: $govuk-error-colour; + } +} diff --git a/app/templates/components/uk_components/error-message/macro-options.json b/app/templates/components/uk_components/error-message/macro-options.json new file mode 100644 index 000000000..eddcab0d2 --- /dev/null +++ b/app/templates/components/uk_components/error-message/macro-options.json @@ -0,0 +1,37 @@ +[ + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within the error message. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within the error message. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "id", + "type": "string", + "required": false, + "description": "Id attribute to add to the error message span tag." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the error message span tag." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the error message span tag" + }, + { + "name": "visuallyHiddenText", + "type": "string", + "description": "A visually hidden prefix used before the error message. Defaults to \"Error\"." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/error-message/macro.njk b/app/templates/components/uk_components/error-message/macro.njk new file mode 100644 index 000000000..053b23bdc --- /dev/null +++ b/app/templates/components/uk_components/error-message/macro.njk @@ -0,0 +1,3 @@ +{% macro govukErrorMessage(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/error-message/template.njk b/app/templates/components/uk_components/error-message/template.njk new file mode 100644 index 000000000..be452167f --- /dev/null +++ b/app/templates/components/uk_components/error-message/template.njk @@ -0,0 +1,6 @@ +{% set visuallyHiddenText = params.visuallyHiddenText | default("Error") -%} + + + {% if visuallyHiddenText %}{{ visuallyHiddenText }}: {% endif -%} + {{ params.html | safe if params.html else params.text }} + diff --git a/app/templates/components/uk_components/fieldset/README.md b/app/templates/components/uk_components/fieldset/README.md new file mode 100644 index 000000000..77381dc4e --- /dev/null +++ b/app/templates/components/uk_components/fieldset/README.md @@ -0,0 +1,15 @@ +# Fieldset + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the fieldset component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/fieldset). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/fieldset/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/fieldset/_fieldset.scss b/app/templates/components/uk_components/fieldset/_fieldset.scss new file mode 100644 index 000000000..fa7728e0f --- /dev/null +++ b/app/templates/components/uk_components/fieldset/_fieldset.scss @@ -0,0 +1,70 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@include govuk-exports("govuk/component/fieldset") { + .govuk-fieldset { + min-width: 0; + margin: 0; + padding: 0; + border: 0; + @include govuk-clearfix; + } + + // Fix for Firefox < 53 + // https://bugzilla.mozilla.org/show_bug.cgi?id=504622 + @supports not (caret-color: auto) { + .govuk-fieldset, + x:-moz-any-link { + display: table-cell; + } + } + + .govuk-fieldset__legend { + @include govuk-font($size: 19); + @include govuk-text-colour; + + // Fix legend text wrapping in Edge and IE + // 1. IE9-11 & Edge 12-13 + // 2. IE8-11 + box-sizing: border-box; // 1 + display: table; // 2 + max-width: 100%; // 1 + margin-bottom: govuk-spacing(2); + padding: 0; + // Hack to let legends or elements within legends have margins in webkit browsers + overflow: hidden; + + white-space: normal; // 1 + } + + // Modifiers that make legends look more like their equivalent headings + + .govuk-fieldset__legend--xl { + @include govuk-font($size: 48, $weight: bold); + margin-bottom: govuk-spacing(3); + } + + .govuk-fieldset__legend--l { + @include govuk-font($size: 36, $weight: bold); + margin-bottom: govuk-spacing(3); + } + + .govuk-fieldset__legend--m { + @include govuk-font($size: 24, $weight: bold); + margin-bottom: govuk-spacing(3); + } + + .govuk-fieldset__legend--s { + @include govuk-font($size: 19, $weight: bold); + } + + // When the legend contains an H1, we want the H1 to inherit all styles from + // the legend. Effectively we want to be able to treat the heading as if it is + // not there. + .govuk-fieldset__heading { + margin: 0; + font-size: inherit; + font-weight: inherit; + } +} diff --git a/app/templates/components/uk_components/fieldset/macro-options.json b/app/templates/components/uk_components/fieldset/macro-options.json new file mode 100644 index 000000000..cd05991ff --- /dev/null +++ b/app/templates/components/uk_components/fieldset/macro-options.json @@ -0,0 +1,58 @@ +[ + { + "name": "describedBy", + "type": "string", + "required": false, + "description": "One or more element IDs to add to the `aria-describedby` attribute, used to provide additional descriptive information for screenreader users." + }, + { + "name": "legend", + "type": "object", + "required": false, + "description": "Options for the legend", + "params": [ + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within the legend. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within the legend. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the legend." + }, + { + "name": "isPageHeading", + "type": "boolean", + "required": false, + "description": "Whether the legend also acts as the heading for the page." + } + ] + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the fieldset container." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the fieldset container." + }, + { + "name": "caller", + "type": "nunjucks-block", + "required": false, + "description": "Not strictly a parameter but [Nunjucks code convention](https://mozilla.github.io/nunjucks/templating.html#call). Using a `call` block enables you to call a macro with all the text inside the tag. This is helpful if you want to pass a lot of content into a macro. To use it, you will need to wrap the entire fielset component in a `call` block. See [checkboxes component](https://github.com/alphagov/govuk-frontend/blob/master/src/components/checkboxes/template.njk#L86) for an example." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/fieldset/macro.njk b/app/templates/components/uk_components/fieldset/macro.njk new file mode 100644 index 000000000..688442182 --- /dev/null +++ b/app/templates/components/uk_components/fieldset/macro.njk @@ -0,0 +1,3 @@ +{% macro govukFieldset(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/fieldset/template.njk b/app/templates/components/uk_components/fieldset/template.njk new file mode 100644 index 000000000..cb0a68344 --- /dev/null +++ b/app/templates/components/uk_components/fieldset/template.njk @@ -0,0 +1,17 @@ +
+ {% if params.legend.html or params.legend.text %} + + {% if params.legend.isPageHeading %} +

+ {{ params.legend.html | safe if params.legend.html else params.legend.text }} +

+ {% else %} + {{ params.legend.html | safe if params.legend.html else params.legend.text }} + {% endif %} +
+ {% endif %} +{{ caller() if caller }} {#- if statement allows usage of `call` to be optional -#} +
diff --git a/app/templates/components/uk_components/footer/README.md b/app/templates/components/uk_components/footer/README.md new file mode 100644 index 000000000..64b7a45ee --- /dev/null +++ b/app/templates/components/uk_components/footer/README.md @@ -0,0 +1,15 @@ +# Footer + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the footer component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/footer). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/footer/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/footer/_footer.scss b/app/templates/components/uk_components/footer/_footer.scss new file mode 100644 index 000000000..9ee8181b9 --- /dev/null +++ b/app/templates/components/uk_components/footer/_footer.scss @@ -0,0 +1,236 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@import "../../helpers/typography"; + +@include govuk-exports("govuk/component/footer") { + + $govuk-footer-background: $govuk-canvas-background-colour; + $govuk-footer-border-top: #a1acb2; + $govuk-footer-border: govuk-colour("grey-2"); + $govuk-footer-text: #454a4c; + $govuk-footer-link: $govuk-footer-text; + $govuk-footer-link-hover: #171819; + + // Based on the govuk-crest-2x.png image dimensions. + $govuk-footer-crest-image-width-2x: 250px; + $govuk-footer-crest-image-height-2x: 204px; + // Half the 2x image so that it fits the regular 1x size. + $govuk-footer-crest-image-width: ($govuk-footer-crest-image-width-2x / 2); + $govuk-footer-crest-image-height: ($govuk-footer-crest-image-height-2x / 2); + + .govuk-footer { + @include govuk-font($size: 16); + @include govuk-responsive-padding(7, "top"); + @include govuk-responsive-padding(5, "bottom"); + + border-top: 1px solid $govuk-footer-border-top; + color: $govuk-footer-text; + background: $govuk-footer-background; + } + + .govuk-footer__link { + @include govuk-focusable-fill; + + &:link, + &:visited { + color: $govuk-footer-link; + } + + &:hover, + &:active { + color: $govuk-footer-link-hover; + } + + // When focussed, the text colour needs to be darker to ensure that colour + // contrast is still acceptable + &:focus { + color: $govuk-focus-text-colour; + } + + // alphagov/govuk_template includes a specific a:link:focus selector + // designed to make unvisited links a slightly darker blue when focussed, so + // we need to override the text colour for that combination of selectors. + @include govuk-compatibility(govuk_template) { + &:link:focus { + @include govuk-text-colour; + } + } + } + + .govuk-footer__section-break { + margin: 0; // Reset `
` default margins + @include govuk-responsive-margin(8, "bottom"); + border: 0; // Reset `
` default borders + border-bottom: 1px solid $govuk-footer-border; + } + + .govuk-footer__meta { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; // Support: Flexbox + margin-right: -$govuk-gutter-half; + margin-left: -$govuk-gutter-half; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; // Support: Flexbox + -webkit-box-align: end; + -webkit-align-items: flex-end; + -ms-flex-align: end; + align-items: flex-end; // Support: Flexbox + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; // Support: Flexbox + } + + .govuk-footer__meta-item { + margin-right: $govuk-gutter-half; + margin-bottom: govuk-spacing(5); + margin-left: $govuk-gutter-half; + } + + .govuk-footer__meta-item--grow { + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; // Support: Flexbox + @include mq ($until: tablet) { + -webkit-flex-basis: 320px; + -ms-flex-preferred-size: 320px; + flex-basis: 320px; // Support: Flexbox + } + } + + .govuk-footer__licence-logo { + display: inline-block; + margin-right: govuk-spacing(2); + @include mq ($until: desktop) { + margin-bottom: govuk-spacing(3); + } + vertical-align: top; + } + + .govuk-footer__licence-description { + display: inline-block; + } + + .govuk-footer__copyright-logo { + display: inline-block; + min-width: $govuk-footer-crest-image-width; + padding-top: ($govuk-footer-crest-image-height + govuk-spacing(2)); + background-image: govuk-image-url("govuk-crest.png"); + @include govuk-device-pixel-ratio { + background-image: govuk-image-url("govuk-crest-2x.png"); + } + background-repeat: no-repeat; + background-position: 50% 0%; + background-size: $govuk-footer-crest-image-width $govuk-footer-crest-image-height; + text-align: center; + text-decoration: none; + white-space: nowrap; + } + + .govuk-footer__inline-list { + margin-top: 0; + margin-bottom: govuk-spacing(3); + padding: 0; + } + + .govuk-footer__meta-custom { + margin-bottom: govuk-spacing(4); + } + + .govuk-footer__inline-list-item { + display: inline-block; + margin-right: govuk-spacing(3); + margin-bottom: govuk-spacing(1); + } + + .govuk-footer__heading { + @include govuk-responsive-margin(7, "bottom"); + padding-bottom: govuk-spacing(4); + @include mq ($until: tablet) { + padding-bottom: govuk-spacing(2); + } + border-bottom: 1px solid $govuk-footer-border; + } + + .govuk-footer__navigation { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; // Support: Flexbox + margin-right: -$govuk-gutter-half; + margin-left: -$govuk-gutter-half; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; // Support: Flexbox + } + + .govuk-footer__section { + display: inline-block; + margin-right: $govuk-gutter-half; + margin-bottom: $govuk-gutter; + margin-left: $govuk-gutter-half; + vertical-align: top; + // Ensure columns take up equal width (typically one-half:one-half) + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; // Support: Flexbox + -webkit-flex-shrink: 1; + -ms-flex-negative: 1; + flex-shrink: 1; // Support: Flexbox + @include mq ($until: desktop) { + // Make sure columns do not drop below 200px in width + // Will typically result in wrapping, and end up in a single column on smaller screens. + -webkit-flex-basis: 200px; + -ms-flex-preferred-size: 200px; + flex-basis: 200px; // Support: Flexbox + } + } + + // Sections two-third:one-third on desktop + @include mq ($from: desktop) { + .govuk-footer__section:first-child { + -webkit-box-flex: 2; + -webkit-flex-grow: 2; + -ms-flex-positive: 2; + flex-grow: 2; // Support: Flexbox + } + } + + .govuk-footer__list { + margin: 0; + padding: 0; + list-style: none; + -webkit-column-gap: $govuk-gutter; + -moz-column-gap: $govuk-gutter; + column-gap: $govuk-gutter; // Support: Columns + } + + @include mq ($from: desktop) { + .govuk-footer__list--columns-2 { + -webkit-column-count: 2; + -moz-column-count: 2; + column-count: 2; // Support: Columns + } + + .govuk-footer__list--columns-3 { + -webkit-column-count: 3; + -moz-column-count: 3; + column-count: 3; // Support: Columns + } + } + + .govuk-footer__list-item { + @include govuk-responsive-margin(4, "bottom"); + } + + .govuk-footer__list-item:last-child { + margin-bottom: 0; + } +} diff --git a/app/templates/components/uk_components/footer/macro-options.json b/app/templates/components/uk_components/footer/macro-options.json new file mode 100644 index 000000000..3c1445cac --- /dev/null +++ b/app/templates/components/uk_components/footer/macro-options.json @@ -0,0 +1,115 @@ +[ + { + "name": "meta", + "type": "object", + "required": false, + "description": "Object containing options for the meta navigation.", + "params": [ + { + "name": "visuallyHiddenTitle", + "type": "string", + "description": "Title for a meta item section, which defaults to Support links" + }, + { + "name": "html", + "type": "string", + "description": "HTML to add to the meta section of the footer, which will appear below any links specified using meta.items." + }, + { + "name": "text", + "type": "string", + "description": "Text to add to the meta section of the footer, which will appear below any links specified using meta.items. If meta.html is specified, this option is ignored." + }, + { + "name": "items", + "type": "array", + "required": false, + "description": "Array of items for use in the meta section of the footer.", + "params": [ + { + "name": "text", + "type": "string", + "required": false, + "description": "List item text in the meta section of the footer." + }, + { + "name": "href", + "type": "string", + "required": false, + "description": "List item href attribute in the meta section of the footer." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the anchor in the footer meta section." + } + ] + } + ] + }, + { + "name": "navigation", + "type": "array", + "required": false, + "description": "Array of items for use in the navigation section of the footer.", + "params": [ + { + "name": "title", + "type": "string", + "required": false, + "description": "Title for a section" + }, + { + "name": "columns", + "type": "integer", + "required": false, + "description": "Amount of columns to display items in navigation section of the footer." + }, + { + "name": "items", + "type": "array", + "required": false, + "description": "Array of items to display in the list in navigation section of the footer.", + "params": [ + { + "name": "text", + "type": "string", + "required": false, + "description": "List item text in the navigation section of the footer." + }, + { + "name": "href", + "type": "string", + "required": false, + "description": "List item href attribute in the navigation section of the footer. Both `text` and `href` attributes need to be present to create a link." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the anchor in the footer navigation section." + } + ] + } + ] + }, + { + "name": "containerClasses", + "type": "string", + "required": false, + "description": "Classes that can be added to the inner container, useful if you want to make the footer full width." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the footer component container." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the footer component container." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/footer/macro.njk b/app/templates/components/uk_components/footer/macro.njk new file mode 100644 index 000000000..22e58680c --- /dev/null +++ b/app/templates/components/uk_components/footer/macro.njk @@ -0,0 +1,3 @@ +{% macro govukFooter(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/footer/template.njk b/app/templates/components/uk_components/footer/template.njk new file mode 100644 index 000000000..1e797312a --- /dev/null +++ b/app/templates/components/uk_components/footer/template.njk @@ -0,0 +1,87 @@ +
+
+ {% if params.navigation %} + + + {% endif %} + +
+
diff --git a/app/templates/components/uk_components/header/README.md b/app/templates/components/uk_components/header/README.md new file mode 100644 index 000000000..5254d0cb2 --- /dev/null +++ b/app/templates/components/uk_components/header/README.md @@ -0,0 +1,15 @@ +# Header + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the header component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/header). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/header/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/header/_header.scss b/app/templates/components/uk_components/header/_header.scss new file mode 100644 index 000000000..ed1cbbb86 --- /dev/null +++ b/app/templates/components/uk_components/header/_header.scss @@ -0,0 +1,303 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@import "../../helpers/typography"; + +@include govuk-exports("govuk/component/header") { + + $govuk-header-background: govuk-colour("black"); + $govuk-header-border-color: $govuk-brand-colour; + $govuk-header-border-width: govuk-spacing(2); + $govuk-header-text: govuk-colour("white"); + $govuk-header-link: govuk-colour("white"); + $govuk-header-link-hover: govuk-colour("white"); + $govuk-header-link-active: #1d8feb; + $govuk-header-nav-item-border-color: #2e3133; + + .govuk-header { + @include govuk-font($size: 16); + + border-bottom: govuk-spacing(2) solid govuk-colour("white"); + color: $govuk-header-text; + background: $govuk-header-background; + + } + + .govuk-header__container--full-width { + padding: 0 govuk-spacing(3); + border-color: $govuk-header-border-color; + + .govuk-header__menu-button { + right: govuk-spacing(3); + } + } + + .govuk-header__container { + @include govuk-clearfix; + position: relative; + margin-bottom: -$govuk-header-border-width; + padding-top: govuk-spacing(2); + border-bottom: $govuk-header-border-width solid $govuk-header-border-color; + } + + .govuk-header__logotype { + margin-right: govuk-spacing(1); + } + + .govuk-header__logotype-crown { + margin-right: 1px; + fill: currentColor; + vertical-align: middle; + } + + .govuk-header__logotype-crown-fallback-image { + width: 36px; + height: 32px; + border: 0; + vertical-align: middle; + } + + .govuk-header__product-name { + @include govuk-font($size: 24); + display: inline-table; + padding-right: govuk-spacing(2); + } + + .govuk-header__link { + @include govuk-focusable-fill; + + text-decoration: none; + + &:link, + &:visited { + color: $govuk-header-link; + } + + &:hover { + text-decoration: underline; + } + + // When focussed, the text colour needs to be darker to ensure that colour + // contrast is still acceptable + &:focus { + color: $govuk-focus-text-colour; + } + + // alphagov/govuk_template includes a specific a:link:focus selector + // designed to make unvisited links a slightly darker blue when focussed, so + // we need to override the text colour for that combination of selectors. + @include govuk-compatibility(govuk_template) { + &:link:focus { + @include govuk-text-colour; + } + } + } + + .govuk-header__link--homepage { + // Font size needs to be set on the link so that the box sizing is correct + // in Firefox + @include govuk-font($size: false, $weight: bold); + + display: inline-block; + font-size: 30px; // We don't have a mixin that produces 30px font size + line-height: 30px; + + &:link, + &:visited { + text-decoration: none; + } + + &:hover, + &:active { + // Negate the added border + margin-bottom: -1px; + // Omitting colour will use default value of currentColor – if we + // specified currentColor explicitly IE8 would ignore this rule. + border-bottom: 1px solid; + } + } + + .govuk-header__link--service-name { + display: inline-block; + margin-bottom: govuk-spacing(2); + @include govuk-font($size: 24, $weight: bold); + } + + .govuk-header__logo, + .govuk-header__content { + box-sizing: border-box; + } + + .govuk-header__logo { + @include govuk-responsive-margin(2, "bottom"); + padding-right: govuk-spacing(8); + + @include mq ($from: desktop) { + width: 33.33%; + padding-right: $govuk-gutter-half; + float: left; + vertical-align: top; + } + } + + .govuk-header__content { + @include mq ($from: desktop) { + width: 66.66%; + padding-left: $govuk-gutter-half; + float: left; + } + } + + .govuk-header__menu-button { + @include govuk-font($size: 16); + display: none; + position: absolute; + top: govuk-spacing(4); + right: 0; + margin: 0; + padding: 0; + border: 0; + color: $govuk-header-link; + background: none; + + &:hover { + text-decoration: underline; + } + + &::after { + @include govuk-shape-arrow($direction: down, $base: 10px, $display: inline-block); + content: ""; + margin-left: govuk-spacing(1); + } + + @include govuk-focusable; + + @include mq ($from: tablet) { + top: govuk-spacing(3); + } + } + + .govuk-header__menu-button--open { + &::after { + @include govuk-shape-arrow($direction: up, $base: 10px, $display: inline-block); + } + } + + .govuk-header__navigation { + @include govuk-responsive-margin(2, "bottom"); + display: block; + margin: 0; + padding: 0; + list-style: none; + } + + .js-enabled { + .govuk-header__menu-button { + display: block; + @include mq ($from: desktop) { + display: none; + } + } + + .govuk-header__navigation { + display: none; + @include mq ($from: desktop) { + display: block; + } + } + + .govuk-header__navigation--open { + display: block; + } + } + + + .govuk-header__navigation--end { + @include mq ($from: desktop) { + margin: 0; + padding: govuk-spacing(1) 0; + text-align: right; + } + } + + .govuk-header__navigation--no-service-name { + padding-top: govuk-spacing(7); + } + + .govuk-header__navigation-item { + padding: govuk-spacing(2) 0; + border-bottom: 1px solid $govuk-header-nav-item-border-color; + + @include mq ($from: desktop) { + display: inline-block; + margin-right: govuk-spacing(3); + padding: govuk-spacing(1) 0; + border: 0; + } + + a { + @include govuk-font($size: 16, $weight: bold); + white-space: nowrap; + } + } + + .govuk-header__navigation-item--active { + a { + &:link, + &:hover, + &:visited { + color: $govuk-header-link-active; + } + + // When focussed, the text colour needs to be darker to ensure that colour + // contrast is still acceptable + &:focus { + color: $govuk-focus-text-colour; + } + } + } + + .govuk-header__navigation-item:last-child { + margin-right: 0; + } + + @include govuk-media-query($media-type: print) { + .govuk-header { + border-bottom-width: 0; + color: govuk-colour("black"); + background: transparent; + } + + // Hide the inverted crown when printing in browsers that don't support SVG. + .govuk-header__logotype-crown-fallback-image { + display: none; + } + + .govuk-header__link { + &:link, + &:visited { + color: govuk-colour("black"); + } + + // Do not append link href to GOV.UK link when printing (e.g. '(/)') + &:after { + display: none; + } + } + } + + // Begin adjustments for font baseline offset + // These should be removed when the font is updated with the correct baseline + .govuk-header__logotype-crown { + position: relative; + top: -4px; + } + + .govuk-header { + $offset: 3px; + padding-top: $offset; + } + // End adjustments + +} diff --git a/app/templates/components/uk_components/header/macro-options.json b/app/templates/components/uk_components/header/macro-options.json new file mode 100644 index 000000000..5d61becb8 --- /dev/null +++ b/app/templates/components/uk_components/header/macro-options.json @@ -0,0 +1,88 @@ +[ + { + "name": "homepageUrl", + "type": "string", + "required": false, + "description": "The url of the homepage. Defaults to /" + }, + { + "name": "assetsPath", + "type": "string", + "required": false, + "description": "The public path for the assets folder. If not provided it defaults to /assets/images" + }, + { + "name": "productName", + "type": "string", + "required": false, + "description": "Header title that is placed next to GOV.UK. Used for product names (i.e. Pay, Verify)" + }, + { + "name": "serviceName", + "type": "string", + "required": false, + "description": "Header title that is placed next to GOV.UK. Used for product names (i.e. Pay, Verify)" + }, + { + "name": "serviceUrl", + "type": "string", + "required": false, + "description": "Url for the service name anchor." + }, + { + "name": "navigation", + "type": "array", + "required": false, + "description": "An array of navigation item objects.", + "params": [ + { + "name": "text", + "type": "string", + "required": false, + "description": "Text of the navigation item." + }, + { + "name": "href", + "type": "string", + "required": false, + "description": "Url of the navigation item anchor. Both `href` and `text` attributes for navigation items need to be provided to create an item." + }, + { + "name": "active", + "type": "boolean", + "required": false, + "description": "Flag to mark the navigation item as active or not." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the navigation item anchor." + } + ] + }, + { + "name": "navigationClasses", + "type": "string", + "required": false, + "description": "Classes for the navigation section of the header." + }, + { + "name": "containerClasses", + "type": "string", + "required": false, + "description": "Classes for the container, useful if you want to make the header fixed width." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the header container." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the header container." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/header/macro.njk b/app/templates/components/uk_components/header/macro.njk new file mode 100644 index 000000000..d863b7831 --- /dev/null +++ b/app/templates/components/uk_components/header/macro.njk @@ -0,0 +1,3 @@ +{% macro govukHeader(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/header/template.njk b/app/templates/components/uk_components/header/template.njk new file mode 100644 index 000000000..b7f27efa7 --- /dev/null +++ b/app/templates/components/uk_components/header/template.njk @@ -0,0 +1,84 @@ + diff --git a/app/templates/components/uk_components/hint/README.md b/app/templates/components/uk_components/hint/README.md new file mode 100644 index 000000000..e87a00ab4 --- /dev/null +++ b/app/templates/components/uk_components/hint/README.md @@ -0,0 +1,15 @@ +# Hint + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +The label component is used in other input components, to see an example of it in use see the [text input component](https://design-system.service.gov.uk/components/text-input/#using-hint-text). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/file-upload/#options-example-default--hint) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/hint/_hint.scss b/app/templates/components/uk_components/hint/_hint.scss new file mode 100644 index 000000000..7dab10c46 --- /dev/null +++ b/app/templates/components/uk_components/hint/_hint.scss @@ -0,0 +1,50 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@include govuk-exports("govuk/component/hint") { + .govuk-hint { + @include govuk-font($size: 19); + + display: block; + + margin-bottom: govuk-spacing(3); + + color: $govuk-secondary-text-colour; + } + + // Reduces margin-bottom of hint when used after the default label (no class) + // or govuk-label--s for better vertical alignment. + + // This adjustment will not work when the label is inside the

, however it + // is unlikely that the default or govuk-label--s class would be used in this + // case. + + // This adjustment will not work in browsers that do not support :not(). + // Users with these browsers will see the default size margin (5px larger). + + .govuk-label:not(.govuk-label--m):not(.govuk-label--l):not(.govuk-label--xl) + .govuk-hint { + margin-bottom: govuk-spacing(2); + } + + // Reduces margin-bottom of hint when used after the default legend (no class) + // or govuk-fieldset__legend--s for better vertical alignment. + + // This adjustment will not work when the legend is outside the

, however + // it is unlikely that the default or govuk-fieldset__legend--s class would be + // used in this case. + + // This adjustment will not work in browsers that do not support :not(). + // Users with these browsers will see the default size margin (5px larger). + + .govuk-fieldset__legend:not(.govuk-fieldset__legend--m):not(.govuk-fieldset__legend--l):not(.govuk-fieldset__legend--xl) + .govuk-hint { + margin-bottom: govuk-spacing(2); + } + + // Reduces visual spacing of legend when there is a hint + + .govuk-fieldset__legend + .govuk-hint, + .govuk-fieldset__legend + .govuk-hint { + margin-top: -(govuk-spacing(1)); + } +} diff --git a/app/templates/components/uk_components/hint/macro-options.json b/app/templates/components/uk_components/hint/macro-options.json new file mode 100644 index 000000000..2e066ddbe --- /dev/null +++ b/app/templates/components/uk_components/hint/macro-options.json @@ -0,0 +1,32 @@ +[ + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within the hint. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within the hint. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "id", + "type": "string", + "required": true, + "description": "Optional id attribute to add to the hint span tag." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the hint span tag." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the hint span tag." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/hint/macro.njk b/app/templates/components/uk_components/hint/macro.njk new file mode 100644 index 000000000..e0a639d75 --- /dev/null +++ b/app/templates/components/uk_components/hint/macro.njk @@ -0,0 +1,3 @@ +{% macro govukHint(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/hint/template.njk b/app/templates/components/uk_components/hint/template.njk new file mode 100644 index 000000000..58350dca0 --- /dev/null +++ b/app/templates/components/uk_components/hint/template.njk @@ -0,0 +1,4 @@ + + {{ params.html | safe if params.html else params.text }} + diff --git a/app/templates/components/uk_components/input/README.md b/app/templates/components/uk_components/input/README.md new file mode 100644 index 000000000..87211de01 --- /dev/null +++ b/app/templates/components/uk_components/input/README.md @@ -0,0 +1,15 @@ +# Input + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the input component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/text-input). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/text-input/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/input/_input.scss b/app/templates/components/uk_components/input/_input.scss new file mode 100644 index 000000000..1dc1f06d3 --- /dev/null +++ b/app/templates/components/uk_components/input/_input.scss @@ -0,0 +1,77 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@import "../error-message/error-message"; +@import "../hint/hint"; +@import "../label/label"; + +@include govuk-exports("govuk/component/input") { + .govuk-input { + @include govuk-font($size: 19); + @include govuk-focusable; + + box-sizing: border-box; + width: 100%; + height: 40px; + margin-top: 0; + + padding: govuk-spacing(1); + // setting any background-color makes text invisible when changing colours to dark backgrounds in Firefox (https://bugzilla.mozilla.org/show_bug.cgi?id=1335476) + // as background-color and color need to always be set together, color should not be set either + border: $govuk-border-width-form-element solid $govuk-input-border-colour; + border-radius: 0; + + // Disable inner shadow and remove rounded corners + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } + + .govuk-input::-webkit-outer-spin-button, + .govuk-input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; + } + + .govuk-input[type="number"] { + -moz-appearance: textfield; + } + + .govuk-input--error { + border: $govuk-border-width-form-element-error solid $govuk-error-colour; + } + + // The ex measurements are based on the number of W's that can fit inside the input + // Extra space is left on the right hand side to allow for the Safari prefill icon + // Linear regression estimation based on visual tests: y = 1.76 + 1.81x + + .govuk-input--width-30 { + max-width: 56ex + 3ex; + } + + .govuk-input--width-20 { + max-width: 38ex + 3ex; + } + + .govuk-input--width-10 { + max-width: 20ex + 3ex; + } + + .govuk-input--width-5 { + max-width: 10.8ex; + } + + .govuk-input--width-4 { + max-width: 9ex; + } + + .govuk-input--width-3 { + max-width: 7.2ex; + } + + .govuk-input--width-2 { + max-width: 5.4ex; + } + +} diff --git a/app/templates/components/uk_components/input/macro-options.json b/app/templates/components/uk_components/input/macro-options.json new file mode 100644 index 000000000..6bf5e41af --- /dev/null +++ b/app/templates/components/uk_components/input/macro-options.json @@ -0,0 +1,91 @@ +[ + { + "name": "id", + "type": "string", + "required": true, + "description": "The id of the input." + }, + { + "name": "name", + "type": "string", + "required": true, + "description": "The name of the input, which is submitted with the form data." + }, + { + "name": "type", + "type": "string", + "required": false, + "description": "Type of input control to render. Defaults to \"text\"." + }, + { + "name": "value", + "type": "string", + "required": false, + "description": "Optional initial value of the input." + }, + { + "name": "describedBy", + "type": "string", + "required": false, + "description": "One or more element IDs to add to the `aria-describedby` attribute, used to provide additional descriptive information for screenreader users." + }, + { + "name": "label", + "type": "object", + "required": true, + "description": "Options for the label component.", + "isComponent": true + }, + { + "name": "hint", + "type": "object", + "required": false, + "description": "Options for the hint component.", + "isComponent": true + }, + { + "name": "errorMessage", + "type": "object", + "required": false, + "description": "Options for the errorMessage component.", + "isComponent": true + }, + { + "name": "formGroup", + "type": "object", + "required": false, + "description": "Options for the form-group wrapper", + "params": [ + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the form group (e.g. to show error state for the whole group)" + } + ] + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the input." + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "description": "Attribute to [identify input purpose](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html), for instance \"postal-code\" or \"username\". See [autofill](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill) for full list of attributes that can be used." + }, + { + "name": "pattern", + "type": "string", + "required": false, + "description": "Attribute to [provide a regular expression pattern](https://www.w3.org/TR/html51/sec-forms.html#the-pattern-attribute), used to match allowed character combinations for the input value." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the anchor tag." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/input/macro.njk b/app/templates/components/uk_components/input/macro.njk new file mode 100644 index 000000000..e512c1864 --- /dev/null +++ b/app/templates/components/uk_components/input/macro.njk @@ -0,0 +1,3 @@ +{% macro govukInput(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/input/template.njk b/app/templates/components/uk_components/input/template.njk new file mode 100644 index 000000000..95cbd9aa8 --- /dev/null +++ b/app/templates/components/uk_components/input/template.njk @@ -0,0 +1,46 @@ +{% from "../error-message/macro.njk" import govukErrorMessage -%} +{% from "../hint/macro.njk" import govukHint %} +{% from "../label/macro.njk" import govukLabel %} + +{#- a record of other elements that we need to associate with the input using + aria-describedby – for example hints or error messages -#} +{% set describedBy = params.describedBy if params.describedBy else "" %} +
+ {{ govukLabel({ + html: params.label.html, + text: params.label.text, + classes: params.label.classes, + isPageHeading: params.label.isPageHeading, + attributes: params.label.attributes, + for: params.id + }) | indent(2) | trim }} +{% if params.hint %} + {% set hintId = params.id + '-hint' %} + {% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %} + {{ govukHint({ + id: hintId, + classes: params.hint.classes, + attributes: params.hint.attributes, + html: params.hint.html, + text: params.hint.text + }) | indent(2) | trim }} +{% endif %} +{% if params.errorMessage %} + {% set errorId = params.id + '-error' %} + {% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %} + {{ govukErrorMessage({ + id: errorId, + classes: params.errorMessage.classes, + attributes: params.errorMessage.attributes, + html: params.errorMessage.html, + text: params.errorMessage.text, + visuallyHiddenText: params.errorMessage.visuallyHiddenText + }) | indent(2) | trim }} +{% endif %} + +
diff --git a/app/templates/components/uk_components/inset-text/README.md b/app/templates/components/uk_components/inset-text/README.md new file mode 100644 index 000000000..b13918cd9 --- /dev/null +++ b/app/templates/components/uk_components/inset-text/README.md @@ -0,0 +1,15 @@ +# Inset text + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the inset text component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/inset-text). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/inset-text/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/inset-text/_inset-text.scss b/app/templates/components/uk_components/inset-text/_inset-text.scss new file mode 100644 index 000000000..524dc50c8 --- /dev/null +++ b/app/templates/components/uk_components/inset-text/_inset-text.scss @@ -0,0 +1,28 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@include govuk-exports("govuk/component/inset-text") { + .govuk-inset-text { + @include govuk-font($size: 19); + @include govuk-text-colour; + padding: govuk-spacing(3); + // Margin top intended to collapse + // This adds an additional 10px to the paragraph above + @include govuk-responsive-margin(6, "top"); + @include govuk-responsive-margin(6, "bottom"); + + clear: both; + + border-left: $govuk-border-width-wide solid $govuk-border-colour; + + > :first-child { + margin-top: 0; + } + + > :only-child, + > :last-child { + margin-bottom: 0; + } + } +} diff --git a/app/templates/components/uk_components/inset-text/macro-options.json b/app/templates/components/uk_components/inset-text/macro-options.json new file mode 100644 index 000000000..da06fae8c --- /dev/null +++ b/app/templates/components/uk_components/inset-text/macro-options.json @@ -0,0 +1,32 @@ +[ + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within the back link component. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within the back link component. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "id", + "type": "string", + "required": false, + "description": "Id attribute to add to the inset text container." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the inset text container." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the inset text container." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/inset-text/macro.njk b/app/templates/components/uk_components/inset-text/macro.njk new file mode 100644 index 000000000..935c8a69c --- /dev/null +++ b/app/templates/components/uk_components/inset-text/macro.njk @@ -0,0 +1,3 @@ +{% macro govukInsetText(params) %} + {%- include './template.njk' -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/inset-text/template.njk b/app/templates/components/uk_components/inset-text/template.njk new file mode 100644 index 000000000..ade008fed --- /dev/null +++ b/app/templates/components/uk_components/inset-text/template.njk @@ -0,0 +1,4 @@ +
+ {{ params.html | safe if params.html else params.text }} +
diff --git a/app/templates/components/uk_components/label/README.md b/app/templates/components/uk_components/label/README.md new file mode 100644 index 000000000..dd2d7b97e --- /dev/null +++ b/app/templates/components/uk_components/label/README.md @@ -0,0 +1,15 @@ +# Label + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +The label component is used in other input components, to see an example of it in use see the [text input component](https://design-system.service.gov.uk/components/text-input/). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/file-upload/#options-example-default--label) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/label/_label.scss b/app/templates/components/uk_components/label/_label.scss new file mode 100644 index 000000000..bfe400e57 --- /dev/null +++ b/app/templates/components/uk_components/label/_label.scss @@ -0,0 +1,45 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@include govuk-exports("govuk/component/label") { + .govuk-label { + @include govuk-font($size: 19); + @include govuk-text-colour; + + display: block; + + margin-bottom: govuk-spacing(1); + } + + // Modifiers that make labels look more like their equivalent headings + + .govuk-label--xl { + @include govuk-font($size: 48, $weight: bold); + margin-bottom: govuk-spacing(3); + } + + .govuk-label--l { + @include govuk-font($size: 36, $weight: bold); + margin-bottom: govuk-spacing(3); + } + + .govuk-label--m { + @include govuk-font($size: 24, $weight: bold); + margin-bottom: govuk-spacing(2); + } + + .govuk-label--s { + @include govuk-font($size: 19, $weight: bold); + } + + // When the label is nested inside a heading, override the heading so that it + // does not have a margin. Effectively we want to be able to treat the heading + // as if it is not there. + // + // This breaks BEM conventions because it exists as a parent of the 'block', + // so we can't really consider an element. + .govuk-label-wrapper { + margin: 0; + } +} diff --git a/app/templates/components/uk_components/label/macro-options.json b/app/templates/components/uk_components/label/macro-options.json new file mode 100644 index 000000000..2b40a9577 --- /dev/null +++ b/app/templates/components/uk_components/label/macro-options.json @@ -0,0 +1,38 @@ +[ + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within the label. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within the label. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "for", + "type": "string", + "required": true, + "description": "The value of the for attribute, the id of the input the label is associated with." + }, + { + "name": "isPageHeading", + "type": "boolean", + "required": false, + "description": "Whether the label also acts as the heading for the page." + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the label tag." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the label tag." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/label/macro.njk b/app/templates/components/uk_components/label/macro.njk new file mode 100644 index 000000000..91f2ed71a --- /dev/null +++ b/app/templates/components/uk_components/label/macro.njk @@ -0,0 +1,3 @@ +{% macro govukLabel(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/label/template.njk b/app/templates/components/uk_components/label/template.njk new file mode 100644 index 000000000..b740e2b3d --- /dev/null +++ b/app/templates/components/uk_components/label/template.njk @@ -0,0 +1,15 @@ +{% if params.html or params.text %} +{% set labelHtml %} + +{% endset %} + +{% if params.isPageHeading %} +

{{ labelHtml | safe | indent(2) }}

+{% else %} +{{ labelHtml | safe }} +{% endif %} +{% endif %} diff --git a/app/templates/components/uk_components/radios/README.md b/app/templates/components/uk_components/radios/README.md new file mode 100644 index 000000000..8a0da19cb --- /dev/null +++ b/app/templates/components/uk_components/radios/README.md @@ -0,0 +1,15 @@ +# Radios + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the radios component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/radios). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/radios/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/radios/_radios.scss b/app/templates/components/uk_components/radios/_radios.scss new file mode 100644 index 000000000..074bb53cc --- /dev/null +++ b/app/templates/components/uk_components/radios/_radios.scss @@ -0,0 +1,348 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@import "../error-message/error-message"; +@import "../fieldset/fieldset"; +@import "../hint/hint"; +@import "../label/label"; + +@include govuk-exports("govuk/component/radios") { + + $govuk-touch-target-size: 44px; + $govuk-radios-size: 40px; + $govuk-small-radios-size: 24px; + $govuk-radios-label-padding-left-right: govuk-spacing(3); + // When the default focus width is used on a curved edge it looks visually smaller. + // So for the circular radios we bump the default to make it look visually consistent. + $govuk-radios-focus-width: $govuk-focus-width + 1px; + + .govuk-radios__item { + @include govuk-font($size: 19); + + display: block; + position: relative; + + min-height: $govuk-radios-size; + + margin-bottom: govuk-spacing(2); + padding-left: $govuk-radios-size; + + clear: left; + } + + .govuk-radios__item:last-child, + .govuk-radios__item:last-of-type { + margin-bottom: 0; + } + + .govuk-radios__input { + $input-offset: ($govuk-touch-target-size - $govuk-radios-size) / 2; + + cursor: pointer; + + // IE8 doesn’t support pseudo-elements, so we don’t want to hide native + // elements there. + @include govuk-not-ie8 { + position: absolute; + + z-index: 1; + top: $input-offset * -1; + left: $input-offset * -1; + + width: $govuk-touch-target-size; + height: $govuk-touch-target-size; + margin: 0; + + opacity: 0; + } + + @include govuk-if-ie8 { + margin-top: 10px; + margin-right: $govuk-radios-size / -2; + margin-left: $govuk-radios-size / -2; + float: left; + + // add focus outline to input + &:focus { + outline: $govuk-focus-width solid $govuk-focus-colour; + } + } + } + + .govuk-radios__label { + display: inline-block; + margin-bottom: 0; + padding: 8px $govuk-radios-label-padding-left-right govuk-spacing(1); + cursor: pointer; + // remove 300ms pause on mobile + -ms-touch-action: manipulation; + touch-action: manipulation; + } + + // ( ) Radio ring + .govuk-radios__label::before { + content: ""; + box-sizing: border-box; + position: absolute; + top: 0; + left: 0; + + width: $govuk-radios-size; + height: $govuk-radios-size; + + border: $govuk-border-width-form-element solid currentColor; + border-radius: 50%; + background: transparent; + } + + // β€’ Radio button + // + // We create the 'button' entirely out of 'border' so that they remain + // 'filled' even when colours are overridden in the browser. + .govuk-radios__label::after { + content: ""; + + position: absolute; + top: govuk-spacing(2); + left: govuk-spacing(2); + + width: 0; + height: 0; + + border: govuk-spacing(2) solid currentColor; + border-radius: 50%; + opacity: 0; + background: currentColor; + } + + .govuk-radios__hint { + display: block; + padding-right: $govuk-radios-label-padding-left-right; + padding-left: $govuk-radios-label-padding-left-right; + } + + // Focused state + .govuk-radios__input:focus + .govuk-radios__label::before { + // Since box-shadows are removed when users customise their colours we set a + // transparent outline that is shown instead. + // https://accessibility.blog.gov.uk/2017/03/27/how-users-change-colours-on-websites/ + outline: $govuk-focus-width solid transparent; + outline-offset: $govuk-focus-width; + box-shadow: 0 0 0 $govuk-radios-focus-width $govuk-focus-colour; + } + + // Selected state + .govuk-radios__input:checked + .govuk-radios__label::after { + opacity: 1; + } + + // Disabled state + .govuk-radios__input:disabled, + .govuk-radios__input:disabled + .govuk-radios__label { + cursor: default; + } + + .govuk-radios__input:disabled + .govuk-radios__label { + opacity: .5; + } + + // ========================================================= + // Inline radios + // ========================================================= + + .govuk-radios--inline { + @include mq ($from: tablet) { + @include govuk-clearfix; + + .govuk-radios__item { + margin-right: govuk-spacing(4); + float: left; + clear: none; + } + } + + // Prevent inline modifier being used with conditional reveals + &.govuk-radios--conditional { + .govuk-radios__item { + margin-right: 0; + float: none; + } + } + } + + // ========================================================= + // Dividers ('or') + // ========================================================= + + .govuk-radios__divider { + $govuk-divider-size: $govuk-radios-size !default; + @include govuk-font($size: 19); + @include govuk-text-colour; + width: $govuk-divider-size; + margin-bottom: govuk-spacing(2); + text-align: center; + } + + // ========================================================= + // Conditional reveals + // ========================================================= + + $conditional-border-width: $govuk-border-width-mobile; + // Calculate the amount of padding needed to keep the border centered against the radios. + $conditional-border-padding: ($govuk-radios-size / 2) - ($conditional-border-width / 2); + // Move the border centered with the radios + $conditional-margin-left: $conditional-border-padding; + // Move the contents of the conditional inline with the label + $conditional-padding-left: $conditional-border-padding + $govuk-radios-label-padding-left-right; + + .govuk-radios__conditional { + @include govuk-responsive-margin(4, "bottom"); + margin-left: $conditional-margin-left; + padding-left: $conditional-padding-left; + border-left: $conditional-border-width solid $govuk-border-colour; + + .js-enabled &--hidden { + display: none; + } + + & > :last-child { + margin-bottom: 0; + } + } + + // ========================================================= + // Small checkboxes + // ========================================================= + + .govuk-radios--small { + + $input-offset: ($govuk-touch-target-size - $govuk-small-radios-size) / 2; + $label-offset: $govuk-touch-target-size - $input-offset; + + .govuk-radios__item { + @include govuk-clearfix; + min-height: 0; + margin-bottom: 0; + padding-left: $label-offset; + float: left; + } + + // Shift the touch target into the left margin so that the visible edge of + // the control is aligned + // + // ┆Which colour is your favourite? + // β”Œβ”†β”€β”€β”€β” + // │┆() β”‚ Purple + // β””β”†β–²β”€β”€β”˜ + // ▲┆└─ Radio pseudo element, aligned with margin + // └─── Touch target (invisible input), shifted into the margin + .govuk-radios__input { + @include govuk-not-ie8 { + left: $input-offset * -1; + } + + @include govuk-if-ie8 { + margin-left: $govuk-small-radios-size * -1; + } + } + + // Adjust the size and position of the label. + // + // Unlike larger radios, we also have to float the label in order to + // 'shrink' it, preventing the hover state from kicking in across the full + // width of the parent element. + .govuk-radios__label { + margin-top: -2px; + padding: 13px govuk-spacing(3) 13px 1px; + float: left; + + @include govuk-media-query($from: tablet) { + padding: 11px govuk-spacing(3) 10px 1px; + } + } + + // ( ) Radio ring + // + // Reduce the size of the control [1], vertically centering it within the + // touch target [2] + .govuk-radios__label::before { + top: $input-offset - $govuk-border-width-form-element; // 2 + width: $govuk-small-radios-size; // 1 + height: $govuk-small-radios-size; // 1 + } + + // β€’ Radio button + // + // Reduce the size of the 'button' and center it within the ring + .govuk-radios__label::after { + top: 14px; + left: 6px; + border-width: 6px; + } + + // Fix position of hint with small radios + // + // Do not use hints with small radios – because they're within the input + // wrapper they trigger the hover state, but clicking them doesn't actually + // activate the control. + // + // (If you do use them, they won't look completely broken... but seriously, + // don't use them) + .govuk-radios__hint { + padding: 0; + clear: both; + pointer-events: none; + } + + // Align conditional reveals with small radios + .govuk-radios__conditional { + $margin-left: ($govuk-small-radios-size / 2) - ($conditional-border-width / 2); + margin-left: $margin-left; + padding-left: $label-offset - ($margin-left + $conditional-border-width); + clear: both; + } + + .govuk-radios__divider { + width: $govuk-small-radios-size; + margin-bottom: govuk-spacing(1); + } + + // Hover state for small radios. + // + // We use a hover state for small radios because the touch target size + // is so much larger than their visible size, and so we need to provide + // feedback to the user as to which radio they will select when their + // cursor is outside of the visible area. + .govuk-radios__item:hover .govuk-radios__input:not(:disabled) + .govuk-radios__label::before { + box-shadow: 0 0 0 $govuk-hover-width $govuk-hover-colour; + } + + // Because we've overridden the border-shadow provided by the focus state, + // we need to redefine that too. + // + // We use two box shadows, one that restores the original focus state [1] + // and another that then applies the hover state [2]. + .govuk-radios__item:hover .govuk-radios__input:focus + .govuk-radios__label::before { + // sass-lint:disable indentation + box-shadow: 0 0 0 $govuk-radios-focus-width $govuk-focus-colour, // 1 + 0 0 0 $govuk-hover-width $govuk-hover-colour; // 2 + } + + // For devices that explicitly don't support hover, don't provide a hover + // state (e.g. on touch devices like iOS). + // + // We can't use `@media (hover: hover)` because we wouldn't get the hover + // state in browsers that don't support `@media (hover)` (like Internet + // Explorer) – so we have to 'undo' the hover state instead. + @media (hover: none), (pointer: coarse) { + .govuk-radios__item:hover .govuk-radios__input:not(:disabled) + .govuk-radios__label::before { + box-shadow: initial; + } + + .govuk-radios__item:hover .govuk-radios__input:focus + .govuk-radios__label::before { + box-shadow: 0 0 0 $govuk-radios-focus-width $govuk-focus-colour; + } + } + } +} diff --git a/app/templates/components/uk_components/radios/macro-options.json b/app/templates/components/uk_components/radios/macro-options.json new file mode 100644 index 000000000..e54fc9142 --- /dev/null +++ b/app/templates/components/uk_components/radios/macro-options.json @@ -0,0 +1,143 @@ +[ + { + "name": "fieldset", + "type": "object", + "required": false, + "description": "Options for the fieldset component (e.g. legend).", + "isComponent": true + }, + { + "name": "hint", + "type": "object", + "required": false, + "description": "Options for the hint component (e.g. text).", + "isComponent": true + }, + { + "name": "errorMessage", + "type": "object", + "required": false, + "description": "Options for the errorMessage component (e.g. text).", + "isComponent": true + }, + { + "name": "formGroup", + "type": "object", + "required": false, + "description": "Options for the form-group wrapper", + "params": [ + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the form group (e.g. to show error state for the whole group)" + } + ] + }, + { + "name": "idPrefix", + "type": "string", + "required": false, + "description": "String to prefix id for each checkbox item if no id is specified on each item. If `idPrefix` is not passed, fallback to using the name attribute instead." + }, + { + "name": "name", + "type": "string", + "required": true, + "description": "Name attribute for each radio item." + }, + { + "name": "items", + "type": "array", + "required": true, + "description": "Array of radio items objects.", + "params": [ + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within each radio item label. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within each radio item label. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "id", + "type": "string", + "required": false, + "description": "Specific id attribute for the radio item. If omitted, then `idPrefix` string will be applied." + }, + { + "name": "value", + "type": "string", + "required": true, + "description": "Value for the radio input." + }, + { + "name": "label", + "type": "object", + "required": false, + "description": "Provide attributes and classes to each radio item label.", + "isComponent": true + }, + { + "name": "hint", + "type": "object", + "required": false, + "description": "Provide hint to each checkbox item.", + "isComponent": true + }, + { + "name": "divider", + "type": "string", + "required": false, + "description": "Divider text to separate radio items, for example the text \"or\"." + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "description": "If true, radio will be checked." + }, + { + "name": "conditional", + "type": "string", + "required": false, + "description": "If true, content provided will be revealed when the item is checked." + }, + { + "name": "conditional.html", + "type": "html", + "required": false, + "description": "Provide content for the conditional reveal." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "description": "If true, radio will be disabled." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the radio input tag." + } + ] + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the radio container." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the radio input tag." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/radios/macro.njk b/app/templates/components/uk_components/radios/macro.njk new file mode 100644 index 000000000..67b4d8b89 --- /dev/null +++ b/app/templates/components/uk_components/radios/macro.njk @@ -0,0 +1,3 @@ +{% macro govukRadios(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/radios/template.njk b/app/templates/components/uk_components/radios/template.njk new file mode 100644 index 000000000..5ef8b832c --- /dev/null +++ b/app/templates/components/uk_components/radios/template.njk @@ -0,0 +1,104 @@ +{% from "../error-message/macro.njk" import govukErrorMessage -%} +{% from "../fieldset/macro.njk" import govukFieldset %} +{% from "../hint/macro.njk" import govukHint %} +{% from "../label/macro.njk" import govukLabel %} + +{#- If an id 'prefix' is not passed, fall back to using the name attribute + instead. We need this for error messages and hints as well -#} +{% set idPrefix = params.idPrefix if params.idPrefix else params.name %} + +{#- a record of other elements that we need to associate with the input using + aria-describedby – for example hints or error messages -#} +{% set describedBy = params.fieldset.describedBy if params.fieldset.describedBy else "" %} + +{% set isConditional = false %} +{% for item in params.items %} + {% if item.conditional %} + {% set isConditional = true %} + {% endif %} +{% endfor %} + +{#- Capture the HTML so we can optionally nest it in a fieldset -#} +{% set innerHtml %} +{% if params.hint %} + {% set hintId = idPrefix + '-hint' %} + {% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %} + {{ govukHint({ + id: hintId, + classes: params.hint.classes, + attributes: params.hint.attributes, + html: params.hint.html, + text: params.hint.text + }) | indent(2) | trim }} +{% endif %} +{% if params.errorMessage %} + {% set errorId = idPrefix + '-error' %} + {% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %} + {{ govukErrorMessage({ + id: errorId, + classes: params.errorMessage.classes, + attributes: params.errorMessage.attributes, + html: params.errorMessage.html, + text: params.errorMessage.text, + visuallyHiddenText: params.errorMessage.visuallyHiddenText + }) | indent(2) | trim }} +{% endif %} +
+ {% for item in params.items %} + {% set id = item.id if item.id else idPrefix + "-" + loop.index %} + {% set conditionalId = "conditional-" + id %} + {%- if item.divider %} +
{{ item.divider }}
+ {%- else %} + {% set hasHint = true if item.hint.text or item.hint.html %} + {% set itemHintId = id + '-item-hint' %} +
+ + {{ govukLabel({ + html: item.html, + text: item.text, + classes: 'govuk-radios__label' + (' ' + item.label.classes if item.label.classes), + attributes: item.label.attributes, + for: id + }) | indent(6) | trim }} + {%- if hasHint %} + {{ govukHint({ + id: itemHintId, + classes: 'govuk-radios__hint', + attributes: item.hint.attributes, + html: item.hint.html, + text: item.hint.text + }) | indent(6) | trim }} + {%- endif %} +
+ {% if item.conditional %} +
+ {{ item.conditional.html | safe }} +
+ {% endif %} + {% endif %} + {% endfor %} +
+{% endset -%} + +
+{% if params.fieldset %} + {% call govukFieldset({ + describedBy: describedBy, + classes: params.fieldset.classes, + attributes: params.fieldset.attributes, + legend: params.fieldset.legend + }) %} + {{ innerHtml | trim | safe }} + {% endcall %} +{% else %} + {{ innerHtml | trim | safe }} +{% endif %} +
diff --git a/app/templates/components/uk_components/skip-link/README.md b/app/templates/components/uk_components/skip-link/README.md new file mode 100644 index 000000000..df5b1b119 --- /dev/null +++ b/app/templates/components/uk_components/skip-link/README.md @@ -0,0 +1,15 @@ +# Skip link + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the skip link component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/skip-link). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/skip-link/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/skip-link/_skip-link.scss b/app/templates/components/uk_components/skip-link/_skip-link.scss new file mode 100644 index 000000000..ddccb1d2e --- /dev/null +++ b/app/templates/components/uk_components/skip-link/_skip-link.scss @@ -0,0 +1,26 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@include govuk-exports("govuk/component/skip-link") { + .govuk-skip-link { + @include govuk-visually-hidden-focusable; + @include govuk-link-common; + @include govuk-link-style-text; + @include govuk-typography-responsive($size: 16); + + display: block; + padding: govuk-spacing(2) govuk-spacing(3); + + // Respect 'display cutout' safe area (avoids notches and rounded corners) + @supports (padding: unquote("max(calc(0px))")) { + $padding-safe-area-right: calc(#{govuk-spacing(3)} + env(safe-area-inset-right)); + $padding-safe-area-left: calc(#{govuk-spacing(3)} + env(safe-area-inset-left)); + + // Use max() to pick largest padding, default or with safe area + // Escaped due to Sass max() vs. CSS native max() + padding-right: unquote("max(#{govuk-spacing(3)}, #{$padding-safe-area-right})"); + padding-left: unquote("max(#{govuk-spacing(3)}, #{$padding-safe-area-left})"); + } + } +} diff --git a/app/templates/components/uk_components/skip-link/macro-options.json b/app/templates/components/uk_components/skip-link/macro-options.json new file mode 100644 index 000000000..619af1d5c --- /dev/null +++ b/app/templates/components/uk_components/skip-link/macro-options.json @@ -0,0 +1,32 @@ +[ + { + "name": "text", + "type": "string", + "required": true, + "description": "If `html` is set, this is not required. Text to use within the skip link component. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "html", + "type": "string", + "required": true, + "description": "If `text` is set, this is not required. HTML to use within the skip link component. If `html` is provided, the `text` argument will be ignored." + }, + { + "name": "href", + "type": "string", + "required": true, + "description": "The value of the skip link href attribute. Defaults to" + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the skip link." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the skip link." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/skip-link/macro.njk b/app/templates/components/uk_components/skip-link/macro.njk new file mode 100644 index 000000000..b5afb0c4e --- /dev/null +++ b/app/templates/components/uk_components/skip-link/macro.njk @@ -0,0 +1,3 @@ +{% macro govukSkipLink(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/skip-link/template.njk b/app/templates/components/uk_components/skip-link/template.njk new file mode 100644 index 000000000..b78695eae --- /dev/null +++ b/app/templates/components/uk_components/skip-link/template.njk @@ -0,0 +1,3 @@ + + {{- params.html | safe if params.html else params.text -}} + diff --git a/app/templates/components/uk_components/textarea/README.md b/app/templates/components/uk_components/textarea/README.md new file mode 100644 index 000000000..72abdfb8e --- /dev/null +++ b/app/templates/components/uk_components/textarea/README.md @@ -0,0 +1,15 @@ +# Textarea + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the textarea component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/textarea). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/textarea/#options-example-default) for details. \ No newline at end of file diff --git a/app/templates/components/uk_components/textarea/_textarea.scss b/app/templates/components/uk_components/textarea/_textarea.scss new file mode 100644 index 000000000..d37145cc5 --- /dev/null +++ b/app/templates/components/uk_components/textarea/_textarea.scss @@ -0,0 +1,32 @@ +@import "../../settings/all"; +@import "../../tools/all"; +@import "../../helpers/all"; + +@import "../error-message/error-message"; +@import "../hint/hint"; +@import "../label/label"; + +@include govuk-exports("govuk/component/textarea") { + .govuk-textarea { + @include govuk-font($size: 19, $line-height: 1.25); + @include govuk-focusable; + + box-sizing: border-box; // should this be global? + display: block; + width: 100%; + min-height: 40px; + @include govuk-responsive-margin(6, "bottom"); + padding: govuk-spacing(1); + + resize: vertical; + + border: $govuk-border-width-form-element solid $govuk-input-border-colour; + border-radius: 0; + + -webkit-appearance: none; + } + + .govuk-textarea--error { + border: $govuk-border-width-form-element-error solid $govuk-error-colour; + } +} diff --git a/app/templates/components/uk_components/textarea/macro-options.json b/app/templates/components/uk_components/textarea/macro-options.json new file mode 100644 index 000000000..ea2eefa9f --- /dev/null +++ b/app/templates/components/uk_components/textarea/macro-options.json @@ -0,0 +1,85 @@ +[ + { + "name": "id", + "type": "string", + "required": true, + "description": "The id of the textarea." + }, + { + "name": "name", + "type": "string", + "required": true, + "description": "The name of the textarea, which is submitted with the form data." + }, + { + "name": "rows", + "type": "string", + "required": false, + "description": "Optional number of textarea rows (default is 5 rows)." + }, + { + "name": "value", + "type": "string", + "required": false, + "description": "Optional initial value of the textarea." + }, + { + "name": "describedBy", + "type": "string", + "required": false, + "description": "One or more element IDs to add to the `aria-describedby` attribute, used to provide additional descriptive information for screenreader users." + }, + { + "name": "label", + "type": "object", + "required": true, + "description": "Options for the label component.", + "isComponent": true + }, + { + "name": "hint", + "type": "object", + "required": false, + "description": "Options for the hint component.", + "isComponent": true + }, + { + "name": "errorMessage", + "type": "object", + "required": false, + "description": "Options for the errorMessage component (e.g. text).", + "isComponent": true + }, + { + "name": "formGroup", + "type": "object", + "required": false, + "description": "Options for the form-group wrapper", + "params": [ + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the form group (e.g. to show error state for the whole group)" + } + ] + }, + { + "name": "classes", + "type": "string", + "required": false, + "description": "Classes to add to the textarea." + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "description": "Attribute to [identify input purpose](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html), for instance \"postal-code\" or \"username\". See [autofill](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill) for full list of attributes that can be used." + }, + { + "name": "attributes", + "type": "object", + "required": false, + "description": "HTML attributes (for example data attributes) to add to the textarea." + } +] \ No newline at end of file diff --git a/app/templates/components/uk_components/textarea/macro.njk b/app/templates/components/uk_components/textarea/macro.njk new file mode 100644 index 000000000..36a1c4ee7 --- /dev/null +++ b/app/templates/components/uk_components/textarea/macro.njk @@ -0,0 +1,3 @@ +{% macro govukTextarea(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/app/templates/components/uk_components/textarea/template.njk b/app/templates/components/uk_components/textarea/template.njk new file mode 100644 index 000000000..56d9cc333 --- /dev/null +++ b/app/templates/components/uk_components/textarea/template.njk @@ -0,0 +1,44 @@ +{% from "../error-message/macro.njk" import govukErrorMessage -%} +{% from "../hint/macro.njk" import govukHint %} +{% from "../label/macro.njk" import govukLabel %} + +{#- a record of other elements that we need to associate with the input using + aria-describedby – for example hints or error messages -#} +{% set describedBy = params.describedBy if params.describedBy else "" %} +
+ {{ govukLabel({ + html: params.label.html, + text: params.label.text, + classes: params.label.classes, + isPageHeading: params.label.isPageHeading, + attributes: params.label.attributes, + for: params.id + }) | indent(2) | trim }} +{% if params.hint %} + {% set hintId = params.id + '-hint' %} + {% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %} + {{ govukHint({ + id: hintId, + classes: params.hint.classes, + attributes: params.hint.attributes, + html: params.hint.html, + text: params.hint.text + }) | indent(2) | trim }} +{% endif %} +{% if params.errorMessage %} + {% set errorId = params.id + '-error' %} + {% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %} + {{ govukErrorMessage({ + id: errorId, + classes: params.errorMessage.classes, + attributes: params.errorMessage.attributes, + html: params.errorMessage.html, + text: params.errorMessage.text, + visuallyHiddenText: params.errorMessage.visuallyHiddenText + }) | indent(2) | trim }} +{% endif %} + +
diff --git a/app/templates/forms/fields/checkboxes/template.njk b/app/templates/forms/fields/checkboxes/template.njk index f16afb376..10d1a7df8 100644 --- a/app/templates/forms/fields/checkboxes/template.njk +++ b/app/templates/forms/fields/checkboxes/template.njk @@ -1,7 +1,7 @@ -{% from "components/error-message/macro.njk" import govukErrorMessage -%} -{% from "components/fieldset/macro.njk" import govukFieldset %} -{% from "components/hint/macro.njk" import govukHint %} -{% from "components/label/macro.njk" import govukLabel %} +{% from "components/uk_components/error-message/macro.njk" import govukErrorMessage -%} +{% from "components/uk_components/fieldset/macro.njk" import govukFieldset %} +{% from "components/uk_components/hint/macro.njk" import govukHint %} +{% from "components/uk_components/label/macro.njk" import govukLabel %} {#- Copied from https://github.com/alphagov/govuk-frontend/blob/v2.13.0/src/components/checkboxes/template.njk diff --git a/app/templates/main_template.html b/app/templates/main_template.html index ca8ac9a8c..e6da3be7b 100644 --- a/app/templates/main_template.html +++ b/app/templates/main_template.html @@ -1,29 +1,26 @@ -{% from "./components/skip-link/macro.njk" import govukSkipLink -%} -{# specify absolute url for the static assets folder e.g. http://wwww.domain.com/assets #} -{%- set assetUrl = assetUrl | default(assetPath) -%} - {% block pageTitle %}GOV.UK - The best place to find government services and information{% endblock %} + {% block pageTitle %}{% endblock %} {# Hardcoded value of $govuk-black #} {# Ensure that older IE versions always render with the correct rendering engine #} {% block headIcons %} - - {# Hardcoded value of $govuk-black #} - - - - + + {# Hardcoded value of $govuk-black #} + + + + {% endblock %} {% block head %}{% endblock %} {# The default og:image is added below head so that scrapers see any custom metatags first, and this is just a fallback #} {# image url needs to be absolute e.g. http://wwww.domain.com/.../govuk-opengraph-image.png #} - + @@ -110,12 +107,7 @@ Sign in - {% endif %} - - - -
@@ -133,15 +125,10 @@