Skip to content

Commit 21f77d7

Browse files
Add stepper input component
1 parent 0f0c14a commit 21f77d7

File tree

17 files changed

+860
-1
lines changed

17 files changed

+860
-1
lines changed

packages/nhsuk-frontend-review/src/layouts/page.njk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
{% from "nhsuk/components/label/macro.njk" import label %}
2828
{% from "nhsuk/components/legend/macro.njk" import legend %}
2929
{% from "nhsuk/components/notification-banner/macro.njk" import notificationBanner %}
30+
{% from "nhsuk/components/stepper-input/macro.njk" import stepperInput %}
3031
{% from "nhsuk/components/pagination/macro.njk" import pagination %}
3132
{% from "nhsuk/components/panel/macro.njk" import panel %}
3233
{% from "nhsuk/components/password-input/macro.njk" import passwordInput %}

packages/nhsuk-frontend/src/nhsuk/components/_index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
@forward "pagination";
2727
@forward "panel";
2828
@forward "checkboxes";
29+
@forward "stepper-input";
2930
@forward "password-input";
3031
@forward "radios";
3132
@forward "select";

packages/nhsuk-frontend/src/nhsuk/components/button/_index.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ $button-shadow-size: $nhsuk-button-shadow-size;
216216
padding-top: 0;
217217
padding-bottom: 0;
218218

219+
// Prevent users from selecting icon button text
220+
// e.g. When double clicking a stepper button
221+
user-select: none;
222+
219223
.nhsuk-icon {
220224
margin: 0 nhsuk-spacing(1);
221225

packages/nhsuk-frontend/src/nhsuk/components/index.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export * from './checkboxes/checkboxes.mjs'
44
export * from './error-summary/error-summary.mjs'
55
export * from './header/header.mjs'
66
export * from './notification-banner/notification-banner.mjs'
7+
export * from './stepper-input/stepper-input.mjs'
78
export * from './password-input/password-input.mjs'
89
export * from './radios/radios.mjs'
910
export * from './skip-link/skip-link.mjs'

packages/nhsuk-frontend/src/nhsuk/components/input/template.njk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
{{ label({
9393
html: params.label.html,
9494
text: params.label.text,
95+
id: params.label.id,
9596
classes: params.label.classes,
9697
size: params.label.size,
9798
isPageHeading: params.label.isPageHeading,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
@use "../../core/settings" as *;
2+
@use "../../core/tools" as *;
3+
@forward "../button";
4+
@forward "../input";
5+
6+
////
7+
/// Stepper input component
8+
///
9+
/// @group components/stepper-input
10+
////
11+
12+
@include nhsuk-exports("nhsuk/components/stepper-input") {
13+
// Hide the buttons by default, JS removes this attribute
14+
.nhsuk-stepper-input__step-down[hidden],
15+
.nhsuk-stepper-input__step-up[hidden] {
16+
display: none;
17+
}
18+
19+
@include nhsuk-media-query($from: mobile) {
20+
.nhsuk-stepper-input__input {
21+
text-align: center;
22+
}
23+
}
24+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@forward ".";
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import {
2+
axe,
3+
getPage,
4+
getOptions,
5+
goToComponent
6+
} from '@nhsuk/frontend-helpers/puppeteer.mjs'
7+
8+
import { examples } from './fixtures.mjs'
9+
10+
describe('Stepper input', () => {
11+
/** @type {Page} */
12+
let page
13+
14+
beforeAll(async () => {
15+
page = await getPage(browser)
16+
})
17+
18+
describe.each(Object.entries(examples))('%s', (name, example) => {
19+
it.each(getOptions(name, example))(
20+
'$title passes accessibility tests',
21+
async (options) => {
22+
await goToComponent(page, 'stepper-input', options)
23+
return expect(axe(page)).resolves.toHaveNoViolations()
24+
}
25+
)
26+
})
27+
})
28+
29+
/**
30+
* @import { Page } from 'puppeteer'
31+
*/
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/**
2+
* Nunjucks macro option examples
3+
*
4+
* @satisfies {{ [example: string]: MacroExample }}
5+
*/
6+
export const examples = {
7+
'default': {
8+
context: {
9+
label: {
10+
text: 'How many images were taken?',
11+
size: 'l',
12+
isPageHeading: true
13+
},
14+
name: 'example',
15+
min: 0
16+
}
17+
},
18+
'with hint': {
19+
context: {
20+
label: {
21+
text: 'How many images were taken?',
22+
size: 'l',
23+
isPageHeading: true
24+
},
25+
hint: {
26+
text: 'Include additional and repeat images'
27+
},
28+
id: 'with-hint-text',
29+
name: 'example',
30+
min: 0
31+
},
32+
screenshot: {
33+
viewports: ['watch', 'mobile', 'tablet', 'desktop']
34+
}
35+
},
36+
'with error message': {
37+
context: {
38+
label: {
39+
text: 'How many images were taken?',
40+
size: 'l',
41+
isPageHeading: true
42+
},
43+
errorMessage: {
44+
text: 'Enter how many images were taken'
45+
},
46+
id: 'with-error-message',
47+
name: 'example',
48+
min: 0
49+
}
50+
},
51+
'with hint and error': {
52+
context: {
53+
label: {
54+
text: 'How many images were taken?',
55+
size: 'l',
56+
isPageHeading: true
57+
},
58+
hint: {
59+
text: 'Include additional and repeat images'
60+
},
61+
errorMessage: {
62+
text: 'Enter how many images were taken'
63+
},
64+
id: 'with-error-message',
65+
name: 'example'
66+
},
67+
screenshot: {
68+
viewports: ['watch', 'mobile', 'tablet', 'desktop']
69+
}
70+
},
71+
'with button text': {
72+
context: {
73+
label: {
74+
text: 'How many images were taken?',
75+
size: 'l',
76+
isPageHeading: true
77+
},
78+
stepDownButton: {
79+
text: 'Decrease'
80+
},
81+
stepUpButton: {
82+
text: 'Increase'
83+
},
84+
id: 'with-button-text',
85+
name: 'example'
86+
}
87+
},
88+
'without page heading': {
89+
context: {
90+
label: {
91+
text: 'How many images were taken?'
92+
},
93+
id: 'without-heading',
94+
name: 'example',
95+
min: 0
96+
}
97+
},
98+
'min': {
99+
context: {
100+
label: {
101+
text: 'How many images were taken?',
102+
size: 'l',
103+
isPageHeading: true
104+
},
105+
id: 'width-class',
106+
name: 'example'
107+
},
108+
variants: [
109+
{
110+
description: 'with 5',
111+
context: {
112+
min: 5
113+
}
114+
},
115+
{
116+
description: 'with 10',
117+
context: {
118+
min: 10
119+
}
120+
}
121+
]
122+
},
123+
'max': {
124+
context: {
125+
label: {
126+
text: 'How many images were taken?',
127+
size: 'l',
128+
isPageHeading: true
129+
},
130+
id: 'width-class',
131+
name: 'example',
132+
min: 0
133+
},
134+
variants: [
135+
{
136+
description: 'with 5',
137+
context: {
138+
max: 5
139+
}
140+
},
141+
{
142+
description: 'with 10',
143+
context: {
144+
max: 10
145+
}
146+
}
147+
]
148+
}
149+
}
150+
151+
/**
152+
* @import { MacroExample } from '@nhsuk/frontend-lib/components.mjs'
153+
*/

0 commit comments

Comments
 (0)