Skip to content

Commit

Permalink
feat(button menu): Button menu updates (#825)
Browse files Browse the repository at this point in the history
* feat(button menu): update the button menu to new specification

This update removes the flexible buttion grouping functionality and makes the component solely
responsible for making a toggle button menu

BREAKING CHANGE: The component no longer handles being a button group, and it no longer responsively
switches between a button group and a button menu

* feat(button menu): wip - continued work on updated button menu

* feat(button menu): wip - work on styles and interaction details

* ci(husky): prevent husky failing on staging deploy

* docs(updating documentation content): updating button menu documentation content

* feat(button menu): final updates to button menu and adjust page header actions

* feat(button menu): create examples for button menu

* feat(button menu): remove menu and menuitem roles and switch to list

This is not a real "menu" in accessibility terms, so the role is incorrect, and using menuitem on the
items removes link/button semantics

* feat(button menu): update tests for new structure and test js and data api

* Changes to button menu guidance

- Added example images
- Updated 'help and feedback' partial
- Reviewed heading levels

* Updating example image

Updating example image

* feat(button menu): styling changes to improve accessibility

* feat(button menu): refactor initMenu method

* refactor(button menu): tidy up for code review

* feat(button menu): updates to identity bar and page header actions

* feat(button menu): changes from code review and add tests for single button instance

* feat(button menu): update examples to use secondary button style, fix chevron alignment

* Button menu updates

- Updated "what's new" on homepage
- Updated Get help and contribute section on button menu page
- Updated example images
- Reverted 'Suggest a change' box

* docs(identity bar component updates): updates to the identity bar component based on the button menu

* docs(updating documentation content): updating identity bar documentation

* docs(updating documentation content): updating button menu documentation

Adding link to GOV.UK Design System button group
Changing multiple mention of default
Changing Github content

* feat(button menu): set default example to use button tags

* docs(updating documentation content): updating button menu documentation

Including content about WCAG failure for using component as menu

* feat(button menu and date picker): update example images to png

* feat(page header actions): update to use moj-button-group instead of button-menu

* feat(button menu): update the nunjucks arguments documentation

* fix(button menu): add in anchor link to button attributes within nunjucks arguments

* fix(button menu): remove space to fix anchor link

* docs(button menu): fix references to input in items text and html docs

* docs(button menu): remove unnecessary govuk button include in default example

* docs(button menu): final few tweaks

* docs(button menu): minor content changes

* docs(identity bar): update relative links in page

* fix(button menu): fix button spacings on very small screens

---------

Co-authored-by: Rob McCarthy <[email protected]>
Co-authored-by: murrlipp <[email protected]>
Co-authored-by: helennickols <[email protected]>
  • Loading branch information
4 people authored Oct 28, 2024
1 parent 5f924eb commit d989f2d
Show file tree
Hide file tree
Showing 48 changed files with 13,696 additions and 9,672 deletions.
68 changes: 40 additions & 28 deletions .eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,30 @@ const mojFilters = require("./src/moj/filters/all");
const nunjucks = require("nunjucks");
const path = require("path");
const { execSync } = require("child_process");
const releasePackage = require('./package/package.json');
const releasePackage = require("./package/package.json");
const sass = require("sass");
const esbuild = require('esbuild');
const esbuild = require("esbuild");

module.exports = function (eleventyConfig) {
/*
* If the node env is 'dev' then we include the src dir allowing components
* under development to be watched and loaded
*/
const templatePaths = process.env.ENV === 'dev' ? [
".",
"src",
"docs/_includes/",
"node_modules/govuk-frontend/dist/",
"node_modules/@ministryofjustice/frontend/",
] : [
".",
"docs/_includes/",
"node_modules/govuk-frontend/dist/",
"node_modules/@ministryofjustice/frontend/",
];
const templatePaths =
process.env.ENV === "dev"
? [
".",
"src",
"docs/_includes/",
"node_modules/govuk-frontend/dist/",
"node_modules/@ministryofjustice/frontend/",
]
: [
".",
"docs/_includes/",
"node_modules/govuk-frontend/dist/",
"node_modules/@ministryofjustice/frontend/",
];

const nunjucksEnv = nunjucks.configure(templatePaths);

Expand All @@ -51,20 +54,20 @@ module.exports = function (eleventyConfig) {
.disable("code")
.use(markdownItAnchor, {
level: [1, 2, 3, 4],
})
}),
);

eleventyConfig.addShortcode("example", function (exampleHref, height) {
let { data, content: nunjucksCode } = matter(
fs
.readFileSync(
path.join(__dirname, "docs", exampleHref, "index.njk"),
"utf8"
"utf8",
)
.trim()
.trim(),
);

nunjucksCode = nunjucksCode.split('<!--no include-->')[0].trim();
nunjucksCode = nunjucksCode.split("<!--no include-->")[0].trim();

const rawHtmlCode = nunjucksEnv.renderString(nunjucksCode);

Expand All @@ -80,7 +83,7 @@ module.exports = function (eleventyConfig) {
jsCode = fs
.readFileSync(
path.join(__dirname, "docs", exampleHref, "script.js"),
"utf8"
"utf8",
)
.trim();
} catch (e) {}
Expand All @@ -89,7 +92,7 @@ module.exports = function (eleventyConfig) {
href: exampleHref,
id: exampleHref.replace(/\//g, "-"),
arguments: data.arguments,
figmaLink : data.figma_link,
figmaLink: data.figma_link,
title: data.title,
height,
nunjucksCode,
Expand All @@ -98,14 +101,17 @@ module.exports = function (eleventyConfig) {
});
});

eleventyConfig.addShortcode("dateInCurrentMonth", (day) => `${day}/${new Date().getMonth()+1}/${new Date().getFullYear()}`);
eleventyConfig.addShortcode(
"dateInCurrentMonth",
(day) => `${day}/${new Date().getMonth() + 1}/${new Date().getFullYear()}`,
);

eleventyConfig.addShortcode("lastUpdated", function (component) {
if (process.env.STAGING) return '';
if (process.env.STAGING) return "";

const dirPath = path.join(__dirname, "src/moj/components", component);
const [commit, lastUpdated] = execSync(
`LANG=en_GB git log -n1 --pretty=format:%H,%ad --date=format:'%e %B %Y' ${dirPath}`
`LANG=en_GB git log -n1 --pretty=format:%H,%ad --date=format:'%e %B %Y' ${dirPath}`,
)
.toString()
.split(",");
Expand Down Expand Up @@ -157,19 +163,25 @@ module.exports = function (eleventyConfig) {
})),
};
}
}
},
);

eleventyConfig.addFilter("getScriptPath", function (inputPath) {
return inputPath.split("/").slice(1, -1).join("/") + "/script.js";
});

eleventyConfig.addFilter("getStylesPath", function (inputPath) {
return inputPath.split("/").slice(1, -1).join("/") + "/style.css";
});

// Rebuild when a change is made to a component template file
eleventyConfig.addWatchTarget("src/moj/components/**/*.njk");

// Copy the docs images to the public assets dir
eleventyConfig.addPassthroughCopy( { "docs/assets/images/": "assets/images/"});
eleventyConfig.setServerPassthroughCopyBehavior('copy')
eleventyConfig.addPassthroughCopy({
"docs/assets/images/": "assets/images/",
});
eleventyConfig.setServerPassthroughCopyBehavior("copy");

// Give gulp a little time..
eleventyConfig.setWatchThrottleWaitTime(100);
Expand All @@ -180,8 +192,8 @@ module.exports = function (eleventyConfig) {
port: 8080,
// Reload once assets have been rebuilt by gulp
watch: [
'public/assets/stylesheets/application.css',
'public/assets/javascript/all.js'
"public/assets/stylesheets/application.css",
"public/assets/javascript/all.js",
],
// Show local network IP addresses for device testing
showAllHosts: true,
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ WORKDIR /app
FROM base AS staging-build
COPY package.json package.json
COPY package-lock.json package-lock.json
COPY .husky/install.mjs .husky/install.mjs
RUN npm ci

COPY docs docs
Expand Down
32 changes: 20 additions & 12 deletions docs/_includes/arguments/button-menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,34 @@

| Name | Type | Required | Description |
| ------------- | ------ | -------- | ------------------------------------------------------------------------- |
| items | array | Yes | An array of button item objects. See [items](#items). |
| buttonClasses | String | No | Classes to add to the button items. |
| attributes | Object | No | HTML attributes (for example data attributes) to add to the button group. |
| items | Array | Yes | An array of button item objects. See [items](#items). |
| button | Object | No | Properties of the menu title button. See [button](#button). |
| attributes | Object | No | HTML attributes (for example data attributes) to add to the button menu container. |

### Button

| Name | Type | Required | Description |
| ------------- | ------ | -------- | ------------------------------------------------------------------------- |
| text | String | Yes | Text for the menu title button. |
| classes | String | No | Classes to add to the menu title button. |


### Items

See the [button component](https://design-system.service.gov.uk/components/button/) in the GOV.UK Design System for more details.

| Name | Type | Required | Description |
| ------------------ | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| element | String | No | 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`. |
| text | String | Yes | 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`. |
| html | String | Yes | 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 | String | Yes | Name for the `input` or `button`. This has no effect on `a` elements. |
| type | String | Yes | Type of `input` or `button`. The options are `button`, `submit` or `reset`. Defaults to `submit`. This has no effect on `a` elements. |
| value | String | Yes | Value for the `button` tag. This has no effect on `a` or `input` elements. |
| disabled | Boolean | No | Whether the button should be disabled. For button and input elements, `disabled` and `aria-disabled` attributes will be set automatically. |
| href | String | No | 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. |
| element | String | No | Whether to use a `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`. |
| text | String | Yes | 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. |
| html | String | Yes | 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. |
| name | String | Yes | Name for the `button`. This has no effect on `a` elements. |
| type | String | Yes | Type of `button`. The options are `button`, `submit` or `reset`. This will always be `button` in the button menu component. This has no effect on `a` elements. |
| value | String | Yes | Value for the `button` tag. This has no effect on `a` elements. |
| disabled | Boolean | No | Whether the button should be disabled. For `button` elements, `disabled` and `aria-disabled` attributes will be set automatically. |
| href | String | No | 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. The `a` tag will be given the `role` of `button`. |
| classes | String | No | Classes to add to the button component. |
| attributes | Object | No | HTML attributes (for example data attributes) to add to the button component. |
| attributes | Object | No | HTML attributes (for example data attributes) to add to the button. |
| preventDoubleClick | Boolean | No | Prevent accidental double clicks on submit buttons from submitting forms multiple times. |

_Warning: If you’re using Nunjucks macros in production be aware that using HTML arguments, or ones ending with `.html` can be at risk from [cross-site scripting](https://en.wikipedia.org/wiki/Cross-site_scripting) attacks. More information about security vulnerabilities can be found in the [Nunjucks documentation](https://mozilla.github.io/nunjucks/api.html#user-defined-templates-warning)._
8 changes: 4 additions & 4 deletions docs/_includes/example.njk
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@
<li class="app-tabs__list-item" role="presentation">
<a class="app-tabs__tab" href="#nunjucks-default-{{ id }}" role="tab" id="tab_nunjucks-default-{{ id }}" aria-controls="nunjucks-default-{{ id }}">Nunjucks <span class="govuk-visually-hidden">({{ title }})</span></a>
</li>
{%- if jsCode %}
{%- if jsCode -%}
<li class="app-tabs__list-item" role="presentation">
<a class="app-tabs__tab" href="#js-default-{{ id }}" role="tab" id="tab_js-default-{{ id }}" aria-controls="js-default-{{ id }}">JavaScript <span class="govuk-visually-hidden">({{ title }})</span></a>
</li>
{% endif -%}
{%- if figmaLink %}
{%- endif -%}
{%- if figmaLink -%}
<li class="app-tabs__list-item" role="presentation">
<a class="app-tabs__tab" href="#figma-default-{{ id }}" role="tab" id="tab_figma-default-{{ id }}" aria-controls="figma-default-{{ id }}">Figma</a>
</li>
{% endif -%}
{%- endif -%}
</ul>

<div class="app-tabs__panel app-tabs__panel--hidden" id="html-default-{{ id }}" data-module="app-copy" role="tabpanel" aria-labelledby="tab_html-default-{{ id }}">
Expand Down
93 changes: 50 additions & 43 deletions docs/_includes/layouts/base.njk
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta name="theme-color" content="#0b0c0c">

<link rel="shortcut icon" href="{{ '/assets/images/favicon.ico' | url }}" type="image/x-icon">
<link rel="apple-touch-icon" href="{{ '/assets/images/moj-apple-touch-icon-180x180.png' | url }}" sizes="180x180">
<link rel="apple-touch-icon" href="{{ '/assets/images/moj-apple-touch-icon-167x167.png' | url }}" sizes="167x167">
<link rel="apple-touch-icon" href="{{ '/assets/images/moj-apple-touch-icon-152x152.png' | url }}" sizes="152x152">
<link rel="apple-touch-icon" href="{{ '/assets/images/moj-apple-touch-icon.png' | url }}">

<meta name="description" content="Design your service using MoJ styles, components and patterns">
<meta property="og:image" content="{{ '/assets/images/moj-opengraph-image.png' | url }}">

<link href="{{ '/assets/stylesheets/application.css' | url }}" rel="stylesheet">
<title>{% block title %}{{ title }} - MoJ Design System{% endblock %}</title>

<script type="module" src="https://www.googletagmanager.com/gtag/js?id=G-VTGX4YLSVL" async></script>
<script type="module" src="{{ '/assets/javascript/jquery.js' | url }}"></script>
<script type="module" src="{{ '/assets/javascript/all.js' | url }}"></script>
</head>
<body class="govuk-template__body">
<script>document.body.className += ' js-enabled' + ('noModule' in HTMLScriptElement.prototype ? ' govuk-frontend-supported' : '');</script>

{% block body %}
<div>
{% include "./partials/header.njk" %}

{% include "./partials/navigation.njk" %}

{% block content %}
<main class="app-prose-scope" role="main">
{{ content | safe }}
</main>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#0b0c0c">
<link rel="shortcut icon"
href="{{ '/assets/images/favicon.ico' | url }}"
type="image/x-icon">
<link rel="apple-touch-icon"
href="{{ '/assets/images/moj-apple-touch-icon-180x180.png' | url }}"
sizes="180x180">
<link rel="apple-touch-icon"
href="{{ '/assets/images/moj-apple-touch-icon-167x167.png' | url }}"
sizes="167x167">
<link rel="apple-touch-icon"
href="{{ '/assets/images/moj-apple-touch-icon-152x152.png' | url }}"
sizes="152x152">
<link rel="apple-touch-icon"
href="{{ '/assets/images/moj-apple-touch-icon.png' | url }}">
<meta name="description"
content="Design your service using MoJ styles, components and patterns">
<meta property="og:image"
content="{{ '/assets/images/moj-opengraph-image.png' | url }}">
<link href="{{ '/assets/stylesheets/application.css' | url }}"
rel="stylesheet">
{% block pageStyles %}{% endblock %}
<title>
{% block title %}{{ title }} - MoJ Design System{% endblock %}
</title>
<script type="module"
src="https://www.googletagmanager.com/gtag/js?id=G-VTGX4YLSVL"
async></script>
<script type="module" src="{{ '/assets/javascript/jquery.js' | url }}"></script>
<script type="module" src="{{ '/assets/javascript/all.js' | url }}"></script>
</head>
<body class="govuk-template__body">
<script>document.body.className += ' js-enabled' + ('noModule' in HTMLScriptElement.prototype ? ' govuk-frontend-supported' : '');</script>
{% block body %}
<div>
{% include "./partials/header.njk" %}
{% include "./partials/navigation.njk" %}
{% block content %}
<main class="app-prose-scope" role="main">
{{ content | safe }}
</main>
{% endblock %}
{% include "./partials/footer.njk" %}
</div>
{% endblock %}

{% include "./partials/footer.njk" %}

</div>
{% endblock %}
{% block pageScripts %}{% endblock %}
</body>
{% block pageScripts %}{% endblock %}
</body>
</html>
Loading

0 comments on commit d989f2d

Please sign in to comment.