@scottish-government/designsystem-react 0.7.1 → 0.8.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/common/AbstractNotificationBanner.d.ts +2 -2
- package/@types/common/ActionLink.d.ts +8 -0
- package/@types/common/FileIcon.d.ts +1 -1
- package/@types/common/Icon.d.ts +1 -1
- package/@types/components/Accordion.d.ts +0 -1
- package/@types/components/Breadcrumbs.d.ts +2 -5
- package/@types/components/Checkbox.d.ts +0 -2
- package/@types/components/ConfirmationMessage.d.ts +1 -1
- package/@types/components/ContentsNav.d.ts +4 -6
- package/@types/components/DatePicker.d.ts +1 -1
- package/@types/components/ErrorSummary.d.ts +3 -4
- package/@types/components/NotificationPanel.d.ts +1 -1
- package/@types/components/Pagination.d.ts +5 -4
- package/@types/components/PhaseBanner.d.ts +0 -1
- package/@types/components/Question.d.ts +1 -1
- package/@types/components/RadioButton.d.ts +0 -1
- package/@types/components/Select.d.ts +0 -7
- package/@types/components/SequentialNavigation.d.ts +4 -4
- package/@types/components/SideNavigation.d.ts +4 -5
- package/@types/components/SiteFooter.d.ts +25 -0
- package/@types/components/SiteHeader.d.ts +10 -3
- package/@types/components/SiteNavigation.d.ts +2 -3
- package/@types/components/SkipLinks.d.ts +3 -4
- package/@types/components/SummaryCard.d.ts +0 -2
- package/@types/components/SummaryList.d.ts +0 -13
- package/@types/components/Tabs.d.ts +0 -1
- package/@types/components/Tag.d.ts +1 -3
- package/@types/components/TaskList.d.ts +1 -0
- package/@types/sgds.d.ts +13 -2
- package/CHANGELOG.md +63 -1
- package/dist/common/AbstractNotificationBanner.jsx +8 -6
- package/dist/common/ActionLink.jsx +19 -0
- package/dist/common/FileIcon.jsx +2 -7
- package/dist/common/Icon.jsx +3 -9
- package/dist/components/Accordion/Accordion.jsx +12 -7
- package/dist/components/Breadcrumbs/Breadcrumbs.jsx +20 -15
- package/dist/components/Checkbox/Checkbox.jsx +4 -29
- package/dist/components/Checkbox/CheckboxGroup.jsx +63 -0
- package/dist/components/ContentsNav/ContentsNav.jsx +27 -16
- package/dist/components/CookieBanner/CookieBanner.jsx +1 -0
- package/dist/components/DatePicker/DatePicker.jsx +5 -5
- package/dist/components/ErrorSummary/ErrorSummary.jsx +28 -18
- package/dist/components/NotificationBanner/NotificationBanner.jsx +2 -2
- package/dist/components/Pagination/Pagination.jsx +42 -22
- package/dist/components/PhaseBanner/PhaseBanner.jsx +3 -3
- package/dist/components/Question/Question.jsx +3 -3
- package/dist/components/RadioButton/RadioButton.jsx +7 -17
- package/dist/components/RadioButton/RadioGroup.jsx +21 -0
- package/dist/components/Select/Select.jsx +4 -7
- package/dist/components/SequentialNavigation/SequentialNavigation.jsx +31 -18
- package/dist/components/SideNavigation/SideNavigation.jsx +17 -16
- package/dist/components/SiteFooter/SiteFooter.jsx +104 -0
- package/dist/components/SiteHeader/SiteHeader.jsx +113 -32
- package/dist/components/SiteNavigation/SiteNavigation.jsx +20 -7
- package/dist/components/SkipLinks/SkipLinks.jsx +10 -10
- package/dist/components/SummaryCard/SummaryCard.jsx +25 -14
- package/dist/components/SummaryList/SummaryList.jsx +65 -47
- package/dist/components/Tabs/Tabs.jsx +6 -6
- package/dist/components/Tag/Tag.jsx +2 -2
- package/dist/components/TaskList/TaskList.jsx +14 -3
- package/dist/components/TextInput/TextInput.jsx +3 -3
- package/dist/components/Textarea/Textarea.jsx +3 -3
- package/dist/hooks/useTracking.js +21 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/context.js +5 -0
- package/package.json +2 -2
- package/src/common/AbstractNotificationBanner.test.tsx +1 -1
- package/src/common/AbstractNotificationBanner.tsx +14 -13
- package/src/common/ActionLink.test.tsx +80 -0
- package/src/common/ActionLink.tsx +27 -0
- package/src/common/ConditionalWrapper.tsx +1 -1
- package/src/common/FileIcon.tsx +7 -11
- package/src/common/HintText.tsx +2 -2
- package/src/common/Icon.tsx +13 -17
- package/src/common/ScreenReaderText.tsx +2 -2
- package/src/common/WrapperTag.tsx +2 -2
- package/src/components/Accordion/Accordion.test.tsx +17 -4
- package/src/components/Accordion/Accordion.tsx +19 -14
- package/src/components/AspectBox/AspectBox.tsx +2 -2
- package/src/components/BackToTop/BackToTop.tsx +2 -2
- package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +79 -48
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +31 -31
- package/src/components/Button/Button.tsx +2 -2
- package/src/components/Checkbox/Checkbox.test.tsx +1 -96
- package/src/components/Checkbox/Checkbox.tsx +8 -55
- package/src/components/Checkbox/CheckboxGroup.test.tsx +37 -0
- package/src/components/Checkbox/CheckboxGroup.tsx +41 -0
- package/src/components/ConfirmationMessage/ConfirmationMessage.tsx +2 -2
- package/src/components/ContentsNav/ContentsNav.test.tsx +40 -51
- package/src/components/ContentsNav/ContentsNav.tsx +32 -25
- package/src/components/CookieBanner/CookieBanner.tsx +3 -3
- package/src/components/DatePicker/DatePicker.test.tsx +1 -1
- package/src/components/DatePicker/DatePicker.tsx +7 -7
- package/src/components/Details/Details.tsx +2 -2
- package/src/components/ErrorMessage/ErrorMessage.tsx +2 -2
- package/src/components/ErrorSummary/ErrorSummary.test.tsx +40 -34
- package/src/components/ErrorSummary/ErrorSummary.tsx +40 -32
- package/src/components/FileDownload/FileDownload.tsx +2 -2
- package/src/components/HideThisPage/HideThisPage.tsx +2 -2
- package/src/components/InsetText/InsetText.tsx +2 -2
- package/src/components/NotificationBanner/NotificationBanner.tsx +6 -7
- package/src/components/NotificationPanel/NotificationPanel.tsx +2 -2
- package/src/components/PageHeader/PageHeader.tsx +2 -2
- package/src/components/PageMetadata/PageMetadata.tsx +4 -5
- package/src/components/Pagination/Pagination.test.tsx +26 -7
- package/src/components/Pagination/Pagination.tsx +70 -36
- package/src/components/PhaseBanner/PhaseBanner.tsx +4 -5
- package/src/components/Question/Question.test.tsx +1 -1
- package/src/components/Question/Question.tsx +5 -5
- package/src/components/RadioButton/RadioButton.test.tsx +7 -126
- package/src/components/RadioButton/RadioButton.tsx +10 -41
- package/src/components/RadioButton/RadioGroup.test.tsx +65 -0
- package/src/components/RadioButton/RadioGroup.tsx +31 -0
- package/src/components/Select/Select.test.tsx +39 -37
- package/src/components/Select/Select.tsx +7 -22
- package/src/components/SequentialNavigation/SequentialNavigation.test.tsx +32 -21
- package/src/components/SequentialNavigation/SequentialNavigation.tsx +52 -30
- package/src/components/SideNavigation/SideNavigation.test.tsx +39 -85
- package/src/components/SideNavigation/SideNavigation.tsx +27 -29
- package/src/components/SiteFooter/SiteFooter.test.tsx +153 -0
- package/src/components/SiteFooter/SiteFooter.tsx +107 -0
- package/src/components/SiteHeader/SiteHeader.test.tsx +87 -79
- package/src/components/SiteHeader/SiteHeader.tsx +103 -40
- package/src/components/SiteNavigation/SiteNavigation.test.tsx +42 -23
- package/src/components/SiteNavigation/SiteNavigation.tsx +28 -16
- package/src/components/SiteSearch/SiteSearch.tsx +2 -2
- package/src/components/SkipLinks/SkipLinks.test.tsx +22 -10
- package/src/components/SkipLinks/SkipLinks.tsx +16 -15
- package/src/components/SummaryCard/SummaryCard.test.tsx +31 -35
- package/src/components/SummaryCard/SummaryCard.tsx +39 -28
- package/src/components/SummaryList/SummaryList.test.tsx +49 -148
- package/src/components/SummaryList/SummaryList.tsx +54 -92
- package/src/components/Table/Table.tsx +2 -2
- package/src/components/Tabs/Tabs.tsx +14 -15
- package/src/components/Tag/Tag.test.tsx +4 -4
- package/src/components/Tag/Tag.tsx +4 -4
- package/src/components/TaskList/TaskList.test.tsx +26 -0
- package/src/components/TaskList/TaskList.tsx +21 -11
- package/src/components/TextInput/TextInput.test.tsx +1 -1
- package/src/components/TextInput/TextInput.tsx +5 -5
- package/src/components/Textarea/Textarea.test.tsx +1 -1
- package/src/components/Textarea/Textarea.tsx +5 -5
- package/src/components/WarningText/WarningText.tsx +2 -2
- package/src/hooks/useTracking.test.tsx +64 -0
- package/src/hooks/useTracking.ts +19 -0
- package/src/utils/context.ts +3 -0
- package/tsconfig.json +1 -1
|
@@ -4,28 +4,20 @@ import Select from './Select';
|
|
|
4
4
|
|
|
5
5
|
const SELECT_ID = 'select-component';
|
|
6
6
|
const LABEL_TEXT = 'choose a component';
|
|
7
|
-
const OPTIONS =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
{
|
|
13
|
-
text: 'Breadcrumbs',
|
|
14
|
-
value: 'breadcrumbs'
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
text: 'Button',
|
|
18
|
-
value: 'button'
|
|
19
|
-
}
|
|
20
|
-
];
|
|
7
|
+
const OPTIONS = <>
|
|
8
|
+
<option value="accordion">Accordion</option>
|
|
9
|
+
<option value="breadcrumbs">Breadcrumbs</option>
|
|
10
|
+
<option value="button">Button</option>
|
|
11
|
+
</>;
|
|
21
12
|
|
|
22
13
|
test('select renders correctly', () => {
|
|
23
14
|
render(
|
|
24
15
|
<Select
|
|
25
16
|
id={SELECT_ID}
|
|
26
17
|
label={LABEL_TEXT}
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
>
|
|
19
|
+
{OPTIONS}
|
|
20
|
+
</Select>
|
|
29
21
|
);
|
|
30
22
|
|
|
31
23
|
const select = screen.getByRole('combobox');
|
|
@@ -55,9 +47,10 @@ test('select with width', () => {
|
|
|
55
47
|
<Select
|
|
56
48
|
id={SELECT_ID}
|
|
57
49
|
label={LABEL_TEXT}
|
|
58
|
-
options={OPTIONS}
|
|
59
50
|
width={SELECTWIDTH}
|
|
60
|
-
|
|
51
|
+
>
|
|
52
|
+
{OPTIONS}
|
|
53
|
+
</Select>
|
|
61
54
|
);
|
|
62
55
|
|
|
63
56
|
const selectWrapper = screen.getByRole('combobox').parentElement;
|
|
@@ -71,9 +64,10 @@ test('select with hint text', () => {
|
|
|
71
64
|
<Select
|
|
72
65
|
id={SELECT_ID}
|
|
73
66
|
label={LABEL_TEXT}
|
|
74
|
-
options={OPTIONS}
|
|
75
67
|
hintText={HINT_TEXT}
|
|
76
|
-
|
|
68
|
+
>
|
|
69
|
+
{OPTIONS}
|
|
70
|
+
</Select>
|
|
77
71
|
);
|
|
78
72
|
|
|
79
73
|
const hintTextEl = screen.getByText(HINT_TEXT);
|
|
@@ -90,9 +84,10 @@ test('select with custom name', () => {
|
|
|
90
84
|
<Select
|
|
91
85
|
id={SELECT_ID}
|
|
92
86
|
label={LABEL_TEXT}
|
|
93
|
-
options={OPTIONS}
|
|
94
87
|
name={SELECT_NAME}
|
|
95
|
-
|
|
88
|
+
>
|
|
89
|
+
{OPTIONS}
|
|
90
|
+
</Select>
|
|
96
91
|
);
|
|
97
92
|
|
|
98
93
|
const select = screen.getByRole('combobox');
|
|
@@ -106,9 +101,10 @@ test('select with blur function', () => {
|
|
|
106
101
|
<Select
|
|
107
102
|
id={SELECT_ID}
|
|
108
103
|
label={LABEL_TEXT}
|
|
109
|
-
options={OPTIONS}
|
|
110
104
|
onBlur={ONBLUR_FUNCTION}
|
|
111
|
-
|
|
105
|
+
>
|
|
106
|
+
{OPTIONS}
|
|
107
|
+
</Select>
|
|
112
108
|
);
|
|
113
109
|
|
|
114
110
|
const select = screen.getByRole('combobox');
|
|
@@ -125,9 +121,10 @@ test('select with change function', () => {
|
|
|
125
121
|
<Select
|
|
126
122
|
id={SELECT_ID}
|
|
127
123
|
label={LABEL_TEXT}
|
|
128
|
-
options={OPTIONS}
|
|
129
124
|
onChange={ONCHANGE_FUNCTION}
|
|
130
|
-
|
|
125
|
+
>
|
|
126
|
+
{OPTIONS}
|
|
127
|
+
</Select>
|
|
131
128
|
);
|
|
132
129
|
|
|
133
130
|
const select = screen.getByRole('combobox');
|
|
@@ -144,9 +141,10 @@ test('select with placeholder option', () => {
|
|
|
144
141
|
<Select
|
|
145
142
|
id={SELECT_ID}
|
|
146
143
|
label={LABEL_TEXT}
|
|
147
|
-
options={OPTIONS}
|
|
148
144
|
placeholder={PLACEHOLDER_TEXT}
|
|
149
|
-
|
|
145
|
+
>
|
|
146
|
+
{OPTIONS}
|
|
147
|
+
</Select>
|
|
150
148
|
);
|
|
151
149
|
|
|
152
150
|
const select = screen.getByRole('combobox');
|
|
@@ -162,9 +160,10 @@ test('select with initial value', () => {
|
|
|
162
160
|
<Select
|
|
163
161
|
id={SELECT_ID}
|
|
164
162
|
label={LABEL_TEXT}
|
|
165
|
-
options={OPTIONS}
|
|
166
163
|
defaultValue={INITIAL_VALUE}
|
|
167
|
-
|
|
164
|
+
>
|
|
165
|
+
{OPTIONS}
|
|
166
|
+
</Select>
|
|
168
167
|
);
|
|
169
168
|
|
|
170
169
|
const select = screen.getByRole('combobox');
|
|
@@ -179,10 +178,11 @@ test('select with error message', () => {
|
|
|
179
178
|
<Select
|
|
180
179
|
id={SELECT_ID}
|
|
181
180
|
label={LABEL_TEXT}
|
|
182
|
-
options={OPTIONS}
|
|
183
|
-
error
|
|
184
181
|
errorMessage={ERROR_MESSAGE_TEXT}
|
|
185
|
-
|
|
182
|
+
hasError
|
|
183
|
+
>
|
|
184
|
+
{OPTIONS}
|
|
185
|
+
</Select>
|
|
186
186
|
);
|
|
187
187
|
|
|
188
188
|
const select = screen.getByRole('combobox');
|
|
@@ -201,9 +201,10 @@ test('passing additional props', () => {
|
|
|
201
201
|
<Select
|
|
202
202
|
id={SELECT_ID}
|
|
203
203
|
label={LABEL_TEXT}
|
|
204
|
-
options={OPTIONS}
|
|
205
204
|
data-test="foo"
|
|
206
|
-
|
|
205
|
+
>
|
|
206
|
+
{OPTIONS}
|
|
207
|
+
</Select>
|
|
207
208
|
);
|
|
208
209
|
|
|
209
210
|
const select = screen.getByRole('combobox');
|
|
@@ -216,9 +217,10 @@ test('passing additional CSS classes', () => {
|
|
|
216
217
|
<Select
|
|
217
218
|
id={SELECT_ID}
|
|
218
219
|
label={LABEL_TEXT}
|
|
219
|
-
options={OPTIONS}
|
|
220
220
|
className="foo"
|
|
221
|
-
|
|
221
|
+
>
|
|
222
|
+
{OPTIONS}
|
|
223
|
+
</Select>
|
|
222
224
|
);
|
|
223
225
|
|
|
224
226
|
const select = screen.getByRole('combobox');
|
|
@@ -1,31 +1,22 @@
|
|
|
1
1
|
import ErrorMessage from '../ErrorMessage/ErrorMessage';
|
|
2
2
|
import HintText from '../../common/HintText';
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
value
|
|
7
|
-
}) {
|
|
8
|
-
return (
|
|
9
|
-
<option value={value}>{text}</option>
|
|
10
|
-
);
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const Select: React.FC<SGDS.Component.Select> = function ({
|
|
4
|
+
const Select = function ({
|
|
5
|
+
children,
|
|
14
6
|
className,
|
|
15
7
|
defaultValue,
|
|
16
|
-
error,
|
|
17
8
|
errorMessage,
|
|
9
|
+
hasError,
|
|
18
10
|
hintText,
|
|
19
11
|
id,
|
|
20
12
|
label,
|
|
21
13
|
name,
|
|
22
14
|
onBlur,
|
|
23
15
|
onChange,
|
|
24
|
-
options,
|
|
25
16
|
placeholder,
|
|
26
17
|
width,
|
|
27
18
|
...props
|
|
28
|
-
}) {
|
|
19
|
+
}: SGDS.Component.Select) {
|
|
29
20
|
const errorMessageId = `error-message-${id}`;
|
|
30
21
|
const hintTextId = `hint-text-${id}`;
|
|
31
22
|
const describedbys: string[] = [];
|
|
@@ -53,7 +44,7 @@ const Select: React.FC<SGDS.Component.Select> = function ({
|
|
|
53
44
|
<div
|
|
54
45
|
className={[
|
|
55
46
|
"ds_select-wrapper",
|
|
56
|
-
|
|
47
|
+
hasError && 'ds_input--error',
|
|
57
48
|
width && `ds_input--${width}`,
|
|
58
49
|
className
|
|
59
50
|
].join(' ')}
|
|
@@ -61,7 +52,7 @@ const Select: React.FC<SGDS.Component.Select> = function ({
|
|
|
61
52
|
>
|
|
62
53
|
<select
|
|
63
54
|
aria-describedby={describedbys.join(' ')}
|
|
64
|
-
aria-invalid={
|
|
55
|
+
aria-invalid={hasError}
|
|
65
56
|
className="ds_select"
|
|
66
57
|
defaultValue={defaultValue}
|
|
67
58
|
id={id}
|
|
@@ -70,13 +61,7 @@ const Select: React.FC<SGDS.Component.Select> = function ({
|
|
|
70
61
|
onChange={handleChange}
|
|
71
62
|
>
|
|
72
63
|
<option value="">{placeholder}</option>
|
|
73
|
-
{
|
|
74
|
-
<Option
|
|
75
|
-
value={option.value}
|
|
76
|
-
text={option.text}
|
|
77
|
-
key={`option-${index}`}
|
|
78
|
-
/>
|
|
79
|
-
))}
|
|
64
|
+
{children}
|
|
80
65
|
</select>
|
|
81
66
|
<span className="ds_select-arrow" aria-hidden="true"></span>
|
|
82
67
|
</div>
|
|
@@ -2,18 +2,23 @@ import { test, expect } from 'vitest';
|
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import SequentialNavigation from './SequentialNavigation';
|
|
4
4
|
|
|
5
|
-
const NEXT_LINK_OBJECT = { title: 'Apply for or renew a Blue Badge?', href: '#
|
|
5
|
+
const NEXT_LINK_OBJECT = { title: 'Apply for or renew a Blue Badge?', href: '#next' }
|
|
6
6
|
const PREVIOUS_LINK_OBJECT = { title: 'Apply for or renew a Blue Badge?', href: '#prev' }
|
|
7
7
|
|
|
8
8
|
test('sequential navigation renders correctly', () => {
|
|
9
9
|
render(
|
|
10
|
-
<SequentialNavigation
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
<SequentialNavigation>
|
|
11
|
+
<SequentialNavigation.Previous href={PREVIOUS_LINK_OBJECT.href}>
|
|
12
|
+
{PREVIOUS_LINK_OBJECT.title}
|
|
13
|
+
</SequentialNavigation.Previous>
|
|
14
|
+
<SequentialNavigation.Next href={NEXT_LINK_OBJECT.href}>
|
|
15
|
+
{NEXT_LINK_OBJECT.title}
|
|
16
|
+
</SequentialNavigation.Next>
|
|
17
|
+
</SequentialNavigation>
|
|
14
18
|
);
|
|
15
19
|
|
|
16
20
|
const sequentialNavigation = screen.getByRole('navigation');
|
|
21
|
+
|
|
17
22
|
const prevLink = screen.getAllByRole('link')[0];
|
|
18
23
|
const prevLinkWrapper = prevLink.parentElement;
|
|
19
24
|
const nextLink = screen.getAllByRole('link')[1];
|
|
@@ -34,18 +39,14 @@ test('sequential navigation renders correctly', () => {
|
|
|
34
39
|
expect(nextLink.textContent).toEqual(NEXT_LINK_OBJECT.title);
|
|
35
40
|
expect(nextLinkWrapper).toHaveClass('ds_sequential-nav__item', 'ds_sequential-nav__item--next');
|
|
36
41
|
expect(nextLinkWrapper?.tagName).toEqual('DIV');
|
|
37
|
-
expect(nextLink.childNodes[0]).toHaveAttribute('data-label', 'Next')
|
|
42
|
+
expect(nextLink.childNodes[0]).toHaveAttribute('data-label', 'Next');
|
|
38
43
|
});
|
|
39
44
|
|
|
40
45
|
test('with custom aria label', () => {
|
|
41
46
|
const ARIA_LABEL = 'My label';
|
|
42
47
|
|
|
43
48
|
render(
|
|
44
|
-
<SequentialNavigation
|
|
45
|
-
ariaLabel={ARIA_LABEL}
|
|
46
|
-
next={NEXT_LINK_OBJECT}
|
|
47
|
-
previous={PREVIOUS_LINK_OBJECT}
|
|
48
|
-
/>
|
|
49
|
+
<SequentialNavigation aria-label={ARIA_LABEL}/>
|
|
49
50
|
);
|
|
50
51
|
|
|
51
52
|
const sequentialNavigation = screen.getByRole('navigation');
|
|
@@ -53,13 +54,27 @@ test('with custom aria label', () => {
|
|
|
53
54
|
expect(sequentialNavigation).toHaveAttribute('aria-label', ARIA_LABEL);
|
|
54
55
|
});
|
|
55
56
|
|
|
57
|
+
test('sequential nav links with custom element', () => {
|
|
58
|
+
render(
|
|
59
|
+
<SequentialNavigation>
|
|
60
|
+
<SequentialNavigation.Previous href={PREVIOUS_LINK_OBJECT.href} linkComponent={
|
|
61
|
+
({ className, ...props }) => (
|
|
62
|
+
<span role="link" className={className} {...props}/>
|
|
63
|
+
)}>
|
|
64
|
+
{PREVIOUS_LINK_OBJECT.title}
|
|
65
|
+
</SequentialNavigation.Previous>
|
|
66
|
+
</SequentialNavigation>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const link = screen.queryByRole('link');
|
|
70
|
+
|
|
71
|
+
expect(link?.tagName).toEqual('SPAN');
|
|
72
|
+
expect(link?.textContent).toEqual(PREVIOUS_LINK_OBJECT.title);
|
|
73
|
+
});
|
|
74
|
+
|
|
56
75
|
test('passing additional props', () => {
|
|
57
76
|
render(
|
|
58
|
-
<SequentialNavigation
|
|
59
|
-
data-test="foo"
|
|
60
|
-
next={NEXT_LINK_OBJECT}
|
|
61
|
-
previous={PREVIOUS_LINK_OBJECT}
|
|
62
|
-
/>
|
|
77
|
+
<SequentialNavigation data-test="foo" />
|
|
63
78
|
);
|
|
64
79
|
|
|
65
80
|
const sequentialNavigation = screen.getByRole('navigation');
|
|
@@ -68,11 +83,7 @@ test('passing additional props', () => {
|
|
|
68
83
|
|
|
69
84
|
test('passing additional CSS classes', () => {
|
|
70
85
|
render(
|
|
71
|
-
<SequentialNavigation
|
|
72
|
-
className="foo"
|
|
73
|
-
next={NEXT_LINK_OBJECT}
|
|
74
|
-
previous={PREVIOUS_LINK_OBJECT}
|
|
75
|
-
/>
|
|
86
|
+
<SequentialNavigation className="foo" />
|
|
76
87
|
);
|
|
77
88
|
|
|
78
89
|
const sequentialNavigation = screen.getByRole('navigation');
|
|
@@ -1,44 +1,63 @@
|
|
|
1
|
-
const
|
|
1
|
+
const SeqNavLink = ({
|
|
2
|
+
children,
|
|
2
3
|
href,
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
isPrev,
|
|
5
|
+
linkComponent,
|
|
6
|
+
textLabel
|
|
7
|
+
}: SGDS.Component.SequentialNavigation.Link) => {
|
|
8
|
+
const LINK_CLASSES = [
|
|
9
|
+
'ds_sequential-nav__button',
|
|
10
|
+
isPrev ? 'ds_sequential-nav__button--left' : 'ds_sequential-nav__button--right'
|
|
11
|
+
].join(' ');
|
|
12
|
+
|
|
13
|
+
const ITEM_CLASSES = [
|
|
14
|
+
'ds_sequential-nav__item',
|
|
15
|
+
isPrev ? 'ds_sequential-nav__item--prev' : 'ds_sequential-nav__item--next'
|
|
16
|
+
].join(' ');
|
|
17
|
+
|
|
18
|
+
function processChildren(children: React.ReactNode) {
|
|
19
|
+
const linkInner = <span className="ds_sequential-nav__text" data-label={textLabel}>{children}</span>
|
|
20
|
+
|
|
21
|
+
if (linkComponent) {
|
|
22
|
+
return linkComponent({ className: LINK_CLASSES, href, children: linkInner });
|
|
23
|
+
} else {
|
|
24
|
+
return <a href={href} className={LINK_CLASSES}>{linkInner}</a>;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
5
28
|
return (
|
|
6
29
|
<div
|
|
7
|
-
className=
|
|
30
|
+
className={ITEM_CLASSES}
|
|
8
31
|
>
|
|
9
|
-
|
|
10
|
-
<span className="ds_sequential-nav__text" data-label="Next">
|
|
11
|
-
{title}
|
|
12
|
-
</span>
|
|
13
|
-
</a>
|
|
32
|
+
{processChildren(children)}
|
|
14
33
|
</div>
|
|
15
|
-
)
|
|
34
|
+
)
|
|
16
35
|
};
|
|
17
36
|
|
|
18
|
-
const
|
|
37
|
+
const NextLink = ({
|
|
38
|
+
children,
|
|
19
39
|
href,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
linkComponent,
|
|
41
|
+
textLabel = 'Next'
|
|
42
|
+
}: SGDS.Component.SequentialNavigation.Link) => {
|
|
43
|
+
return <SeqNavLink href={href} linkComponent={linkComponent} textLabel={textLabel}>{children}</SeqNavLink>
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const PreviousLink = ({
|
|
47
|
+
children,
|
|
48
|
+
href,
|
|
49
|
+
linkComponent,
|
|
50
|
+
textLabel = 'Previous'
|
|
51
|
+
}: SGDS.Component.SequentialNavigation.Link) => {
|
|
52
|
+
return <SeqNavLink href={href} linkComponent={linkComponent} textLabel={textLabel} isPrev>{children}</SeqNavLink>
|
|
33
53
|
};
|
|
34
54
|
|
|
35
|
-
const SequentialNavigation
|
|
55
|
+
const SequentialNavigation = ({
|
|
36
56
|
ariaLabel = 'Article navigation',
|
|
57
|
+
children,
|
|
37
58
|
className,
|
|
38
|
-
next,
|
|
39
|
-
previous,
|
|
40
59
|
...props
|
|
41
|
-
}) => {
|
|
60
|
+
}: SGDS.Component.SequentialNavigation) => {
|
|
42
61
|
return (
|
|
43
62
|
<nav
|
|
44
63
|
className={[
|
|
@@ -48,12 +67,15 @@ const SequentialNavigation: React.FC<SGDS.Component.SequentialNavigation> = ({
|
|
|
48
67
|
aria-label={ariaLabel}
|
|
49
68
|
{...props}
|
|
50
69
|
>
|
|
51
|
-
{
|
|
52
|
-
{next && <NextLink href={next.href} title={next.title}></NextLink>}
|
|
70
|
+
{children}
|
|
53
71
|
</nav>
|
|
54
72
|
);
|
|
55
73
|
};
|
|
56
74
|
|
|
57
75
|
SequentialNavigation.displayName = 'SequentialNavigation';
|
|
76
|
+
SequentialNavigation.Next = NextLink;
|
|
77
|
+
SequentialNavigation.Previous = PreviousLink;
|
|
78
|
+
NextLink.displayName = 'SequentialNavigation.Next';
|
|
79
|
+
PreviousLink.displayName = 'SequentialNavigation.Previous';
|
|
58
80
|
|
|
59
81
|
export default SequentialNavigation;
|
|
@@ -1,49 +1,27 @@
|
|
|
1
1
|
import { test, expect } from 'vitest';
|
|
2
2
|
import { render, screen, within } from '@testing-library/react';
|
|
3
|
-
import SideNavigation
|
|
4
|
-
|
|
5
|
-
const ITEMS = [
|
|
6
|
-
{
|
|
7
|
-
title: 'Apples',
|
|
8
|
-
href: '#apples',
|
|
9
|
-
items: [
|
|
10
|
-
{
|
|
11
|
-
title: 'Green apples',
|
|
12
|
-
href: '#green-apples',
|
|
13
|
-
items: [
|
|
14
|
-
{
|
|
15
|
-
title: 'Bramley',
|
|
16
|
-
current: true
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
title: 'Granny Smith',
|
|
20
|
-
href: '#granny-smith'
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
title: 'Red apples',
|
|
26
|
-
href: '#red-apples'
|
|
27
|
-
}
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
title: 'Bananas',
|
|
32
|
-
href: '#bananas'
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
title: 'Cherries',
|
|
36
|
-
href: '#cherries'
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
title: 'Dates',
|
|
40
|
-
href: '#dates'
|
|
41
|
-
}
|
|
42
|
-
];
|
|
3
|
+
import SideNavigation from './SideNavigation';
|
|
43
4
|
|
|
44
5
|
test('side navigation renders correctly', () => {
|
|
45
6
|
render(
|
|
46
|
-
<SideNavigation
|
|
7
|
+
<SideNavigation>
|
|
8
|
+
<SideNavigation.List isRoot>
|
|
9
|
+
<SideNavigation.Item href="#apples" title="Apples">
|
|
10
|
+
<SideNavigation.List>
|
|
11
|
+
<SideNavigation.Item href="#green-apples" title="Green apples">
|
|
12
|
+
<SideNavigation.List>
|
|
13
|
+
<SideNavigation.Item href="#bramley" title="Bramley" current/>
|
|
14
|
+
<SideNavigation.Item href="#granny-smith" title="Granny smith"/>
|
|
15
|
+
</SideNavigation.List>
|
|
16
|
+
</SideNavigation.Item>
|
|
17
|
+
<SideNavigation.Item href="#red-apples" title="Red apples"/>
|
|
18
|
+
</SideNavigation.List>
|
|
19
|
+
</SideNavigation.Item>
|
|
20
|
+
<SideNavigation.Item href="#bananas" title="Bananas" />
|
|
21
|
+
<SideNavigation.Item href="#cherries" title="Cherries" />
|
|
22
|
+
<SideNavigation.Item href="#dates" title="Dates"/>
|
|
23
|
+
</SideNavigation.List>
|
|
24
|
+
</SideNavigation>
|
|
47
25
|
);
|
|
48
26
|
|
|
49
27
|
const sideNavigation = screen.getByRole('navigation');
|
|
@@ -63,16 +41,11 @@ test('side navigation renders correctly', () => {
|
|
|
63
41
|
expect(label?.textContent).toEqual('Show all Pages in this section');
|
|
64
42
|
|
|
65
43
|
expect(rootList).toHaveAttribute('id', 'side-navigation-root');
|
|
66
|
-
|
|
67
|
-
// some specifics of this case
|
|
68
|
-
expect(rootList.children.length).toEqual(4);
|
|
69
|
-
expect(document.querySelectorAll('.ds_side-navigation__link').length).toEqual(8);
|
|
70
|
-
expect(document.querySelectorAll('.ds_side-navigation__list').length).toEqual(3);
|
|
71
44
|
});
|
|
72
45
|
|
|
73
46
|
test('side nav link renders correctly', () => {
|
|
74
47
|
render(
|
|
75
|
-
<
|
|
48
|
+
<SideNavigation.Item href="#green-apples" title="Green apples" />
|
|
76
49
|
);
|
|
77
50
|
|
|
78
51
|
const item = screen.getByRole('listitem');
|
|
@@ -87,7 +60,7 @@ test('side nav link renders correctly', () => {
|
|
|
87
60
|
|
|
88
61
|
test('current side nav item without link renders correctly', () => {
|
|
89
62
|
render(
|
|
90
|
-
<
|
|
63
|
+
<SideNavigation.Item href="#green-apples" title="Green apples" current />
|
|
91
64
|
);
|
|
92
65
|
|
|
93
66
|
const item = screen.getByRole('listitem');
|
|
@@ -99,22 +72,18 @@ test('current side nav item without link renders correctly', () => {
|
|
|
99
72
|
|
|
100
73
|
test('side nav link with children', () => {
|
|
101
74
|
render(
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
title: 'Granny Smith',
|
|
108
|
-
href: '#granny-smith'
|
|
109
|
-
}]} />
|
|
75
|
+
<SideNavigation.Item href="#green-apples" title="Green apples">
|
|
76
|
+
<SideNavigation.List>
|
|
77
|
+
<SideNavigation.Item href="#bramley" title="Bramley" />
|
|
78
|
+
</SideNavigation.List>
|
|
79
|
+
</SideNavigation.Item>
|
|
110
80
|
);
|
|
111
81
|
|
|
112
82
|
const childList = screen.getByRole('list');
|
|
113
|
-
const childItem =
|
|
83
|
+
const childItem = within(childList).getByRole('listitem');
|
|
114
84
|
const childLink = within(childItem).getByRole('link');
|
|
115
85
|
|
|
116
86
|
expect(childList).toHaveClass('ds_side-navigation__list');
|
|
117
|
-
expect(childList.children.length).toEqual(2);
|
|
118
87
|
|
|
119
88
|
// check properties of first child link
|
|
120
89
|
expect(childItem).toHaveClass('ds_side-navigation__item');
|
|
@@ -123,41 +92,26 @@ test('side nav link with children', () => {
|
|
|
123
92
|
expect(childLink.textContent).toEqual('Bramley');
|
|
124
93
|
});
|
|
125
94
|
|
|
126
|
-
test('side nav
|
|
127
|
-
const
|
|
128
|
-
{
|
|
129
|
-
title: 'Bramley',
|
|
130
|
-
href: '#bramley'
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
title: 'Granny Smith',
|
|
134
|
-
href: '#granny-smith'
|
|
135
|
-
}
|
|
136
|
-
];
|
|
95
|
+
test('side nav link with custom element', () => {
|
|
96
|
+
const LINK_TEXT = 'Green apples'
|
|
137
97
|
|
|
138
98
|
render(
|
|
139
|
-
<
|
|
99
|
+
<SideNavigation.Item href="#green-apples" title={LINK_TEXT} linkComponent={
|
|
100
|
+
({ className, ...props }) => (
|
|
101
|
+
<span role="link" className={className} {...props}/>
|
|
102
|
+
)}/>
|
|
140
103
|
);
|
|
141
104
|
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
const link = within(item).getByRole('link');
|
|
145
|
-
|
|
146
|
-
expect(list).toHaveClass('ds_side-navigation__list');
|
|
147
|
-
expect(list.tagName).toEqual('UL');
|
|
148
|
-
|
|
149
|
-
expect(list.children.length).toEqual(ITEMS.length);
|
|
105
|
+
const item = screen.getByRole('listitem');
|
|
106
|
+
const link = within(item).queryByRole('link');
|
|
150
107
|
|
|
151
|
-
|
|
152
|
-
expect(
|
|
153
|
-
expect(link).toHaveClass('ds_side-navigation__link');
|
|
154
|
-
expect(link).toHaveAttribute('href', '#bramley');
|
|
155
|
-
expect(link.textContent).toEqual('Bramley');
|
|
108
|
+
expect(link?.tagName).toEqual('SPAN');
|
|
109
|
+
expect(link?.textContent).toEqual(LINK_TEXT);
|
|
156
110
|
});
|
|
157
111
|
|
|
158
112
|
test('passing additional props', () => {
|
|
159
113
|
render(
|
|
160
|
-
<SideNavigation data-test="foo"
|
|
114
|
+
<SideNavigation data-test="foo" />
|
|
161
115
|
);
|
|
162
116
|
|
|
163
117
|
const sideNavigation = screen.getByRole('navigation');
|
|
@@ -166,7 +120,7 @@ test('passing additional props', () => {
|
|
|
166
120
|
|
|
167
121
|
test('passing additional CSS classes', () => {
|
|
168
122
|
render(
|
|
169
|
-
<SideNavigation className="foo"
|
|
123
|
+
<SideNavigation className="foo" />
|
|
170
124
|
);
|
|
171
125
|
|
|
172
126
|
const sideNavigation = screen.getByRole('navigation');
|