@scottish-government/designsystem-react 0.7.1 → 0.8.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/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 +2 -2
- package/dist/components/Breadcrumbs/Breadcrumbs.jsx +20 -15
- package/dist/components/Checkbox/Checkbox.jsx +2 -30
- package/dist/components/Checkbox/CheckboxGroup.jsx +69 -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 +3 -17
- package/dist/components/RadioButton/RadioGroup.jsx +61 -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/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- 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 +1 -1
- package/src/components/Accordion/Accordion.tsx +6 -7
- package/src/components/AspectBox/AspectBox.tsx +2 -2
- package/src/components/BackToTop/BackToTop.tsx +2 -2
- package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +79 -47
- 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 +3 -55
- package/src/components/Checkbox/CheckboxGroup.test.tsx +37 -0
- package/src/components/Checkbox/CheckboxGroup.tsx +46 -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 +4 -41
- package/src/components/RadioButton/RadioGroup.test.tsx +65 -0
- package/src/components/RadioButton/RadioGroup.tsx +38 -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
|
@@ -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');
|
|
@@ -2,60 +2,55 @@ import { useEffect, useRef } from 'react';
|
|
|
2
2
|
// @ts-ignore
|
|
3
3
|
import DSSideNavigation from '@scottish-government/design-system/src/components/side-navigation/side-navigation';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}) {
|
|
5
|
+
const SideNavigationList = function ({
|
|
6
|
+
children,
|
|
7
|
+
isRoot
|
|
8
|
+
}: SGDS.Component.SideNavigation.List) {
|
|
9
9
|
return (
|
|
10
10
|
<ul className="ds_side-navigation__list"
|
|
11
|
-
id={
|
|
11
|
+
id={isRoot ? 'side-navigation-root' : undefined }
|
|
12
12
|
>
|
|
13
|
-
{
|
|
14
|
-
<Link
|
|
15
|
-
title={item.title}
|
|
16
|
-
href={item.href}
|
|
17
|
-
items={item.items}
|
|
18
|
-
current={item.current}
|
|
19
|
-
key={'sidenavitem' + index}
|
|
20
|
-
/>
|
|
21
|
-
))}
|
|
13
|
+
{children}
|
|
22
14
|
</ul>
|
|
23
15
|
);
|
|
24
16
|
};
|
|
25
17
|
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
const SideNavigationItem = function ({
|
|
19
|
+
children,
|
|
28
20
|
href,
|
|
29
|
-
|
|
21
|
+
current = false,
|
|
22
|
+
linkComponent,
|
|
30
23
|
title
|
|
31
|
-
}) {
|
|
24
|
+
}: SGDS.Component.SideNavigation.Item) {
|
|
25
|
+
const LINK_CLASS = 'ds_side-navigation__link';
|
|
26
|
+
|
|
32
27
|
return (
|
|
33
28
|
<li
|
|
34
29
|
className={[
|
|
35
30
|
'ds_side-navigation__item',
|
|
36
|
-
|
|
31
|
+
children && 'ds_side-navigation__item--has-children'
|
|
37
32
|
].join(' ')}
|
|
38
33
|
>
|
|
39
34
|
{current ?
|
|
40
|
-
<span className=
|
|
41
|
-
|
|
35
|
+
<span className={LINK_CLASS + ' ds_current'}>{title}</span> :
|
|
36
|
+
linkComponent ? linkComponent({ className: LINK_CLASS, href, children: title }) :
|
|
37
|
+
<a href={href} className={LINK_CLASS}>{title}</a>
|
|
42
38
|
}
|
|
43
39
|
|
|
44
|
-
{
|
|
40
|
+
{children}
|
|
45
41
|
</li>
|
|
46
42
|
);
|
|
47
43
|
};
|
|
48
44
|
|
|
49
|
-
const SideNavigation
|
|
45
|
+
const SideNavigation = function ({
|
|
50
46
|
children,
|
|
51
47
|
className,
|
|
52
|
-
items,
|
|
53
48
|
...props
|
|
54
|
-
}) {
|
|
49
|
+
}: SGDS.Component.SideNavigation) {
|
|
55
50
|
const ref = useRef(null);
|
|
56
51
|
|
|
57
52
|
useEffect(() => {
|
|
58
|
-
if (ref.current) {
|
|
53
|
+
if (ref.current && children) {
|
|
59
54
|
new DSSideNavigation(ref.current).init();
|
|
60
55
|
}
|
|
61
56
|
}, [ref]);
|
|
@@ -77,13 +72,16 @@ const SideNavigation: React.FC<SGDS.Component.SideNavigation> = function ({
|
|
|
77
72
|
<span className="ds_side-navigation__expand-indicator"></span>
|
|
78
73
|
</label>
|
|
79
74
|
|
|
80
|
-
{
|
|
75
|
+
{children}
|
|
81
76
|
</nav>
|
|
82
77
|
);
|
|
83
78
|
};
|
|
84
79
|
|
|
85
80
|
SideNavigation.displayName = 'SideNavigation';
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
SideNavigationItem.displayName = 'SideNavigation.Item';
|
|
82
|
+
SideNavigationList.displayName = 'SideNavigation.List';
|
|
83
|
+
|
|
84
|
+
SideNavigation.Item = SideNavigationItem;
|
|
85
|
+
SideNavigation.List = SideNavigationList;
|
|
88
86
|
|
|
89
87
|
export default SideNavigation;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { test, expect } from 'vitest';
|
|
2
|
+
import { render, screen, within } from '@testing-library/react';
|
|
3
|
+
import SiteFooter from './SiteFooter';
|
|
4
|
+
|
|
5
|
+
const LINK_HREF = '#cookies';
|
|
6
|
+
const LINK_TEXT = 'Cookies';
|
|
7
|
+
|
|
8
|
+
test('site footer renders correctly', () => {
|
|
9
|
+
render(
|
|
10
|
+
<SiteFooter data-testid="sitefooter">
|
|
11
|
+
<SiteFooter.Links data-testid="sitefooterlinks" />
|
|
12
|
+
<SiteFooter.License data-testid="sitefooterlicense" />
|
|
13
|
+
<SiteFooter.Org data-testid="sitefooterorg" />
|
|
14
|
+
</SiteFooter>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const siteFooter = screen.getByTestId('sitefooter');
|
|
18
|
+
const siteFooterWrapper = siteFooter.children[0];
|
|
19
|
+
const siteFooterContent = siteFooterWrapper.children[0];
|
|
20
|
+
|
|
21
|
+
const siteFooterLinksContainer = screen.getByTestId('sitefooterlinks');
|
|
22
|
+
const siteFooterLicenseContainer = screen.getByTestId('sitefooterlicense');
|
|
23
|
+
const siteFooterOrgContainer = screen.getByTestId('sitefooterorg');
|
|
24
|
+
|
|
25
|
+
expect(siteFooter).toHaveClass('ds_site-footer');
|
|
26
|
+
expect(siteFooter.tagName).toEqual('FOOTER');
|
|
27
|
+
|
|
28
|
+
expect(siteFooterWrapper).toHaveClass('ds_wrapper');
|
|
29
|
+
expect(siteFooterWrapper.tagName).toEqual('DIV');
|
|
30
|
+
|
|
31
|
+
expect(siteFooterContent).toHaveClass('ds_site-footer__content');
|
|
32
|
+
expect(siteFooterContent.tagName).toEqual('DIV');
|
|
33
|
+
|
|
34
|
+
expect(siteFooterLinksContainer).toHaveClass('ds_site-footer__site-items');
|
|
35
|
+
expect(siteFooterLinksContainer.tagName).toEqual('UL');
|
|
36
|
+
|
|
37
|
+
expect(siteFooterLicenseContainer).toHaveClass('ds_site-footer__copyright');
|
|
38
|
+
expect(siteFooterLicenseContainer.tagName).toEqual('DIV');
|
|
39
|
+
|
|
40
|
+
expect(siteFooterOrgContainer).toHaveClass('ds_site-footer__org');
|
|
41
|
+
expect(siteFooterOrgContainer.tagName).toEqual('DIV');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('site footer links render correctly', () => {
|
|
45
|
+
render(
|
|
46
|
+
<SiteFooter.Link href={LINK_HREF}>{LINK_TEXT}</SiteFooter.Link>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const listItem = screen.getByRole('listitem');
|
|
50
|
+
const link = within(listItem).getByRole('link');
|
|
51
|
+
|
|
52
|
+
expect(listItem).toHaveClass('ds_site-items__item');
|
|
53
|
+
expect(link).toHaveAttribute('href', LINK_HREF);
|
|
54
|
+
expect(link.textContent).toEqual(LINK_TEXT);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('site footer links with custom element render correctly', () => {
|
|
58
|
+
render(
|
|
59
|
+
<SiteFooter.Link href={LINK_HREF} linkComponent={
|
|
60
|
+
({ className, ...props }) => (
|
|
61
|
+
<span role="link" className={className} {...props}/>
|
|
62
|
+
)}>
|
|
63
|
+
{LINK_TEXT}
|
|
64
|
+
</SiteFooter.Link>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const listItem = screen.getByRole('listitem');
|
|
68
|
+
const link = within(listItem).getByRole('link');
|
|
69
|
+
|
|
70
|
+
expect(listItem).toHaveClass('ds_site-items__item');
|
|
71
|
+
expect(link).toHaveAttribute('href', LINK_HREF);
|
|
72
|
+
expect(link.textContent).toEqual(LINK_TEXT);
|
|
73
|
+
expect(link.tagName).toEqual('SPAN');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('site footer links with no href render correctly', () => {
|
|
77
|
+
render(
|
|
78
|
+
<SiteFooter.Link>{LINK_TEXT}</SiteFooter.Link>
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const listItem = screen.getByRole('listitem');
|
|
82
|
+
const link = within(listItem).queryByRole('link');
|
|
83
|
+
|
|
84
|
+
expect(listItem).toHaveClass('ds_site-items__item');
|
|
85
|
+
expect(listItem.textContent).toEqual(LINK_TEXT);
|
|
86
|
+
expect(link).not.toBeInTheDocument();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('site footer org renders correctly', () => {
|
|
90
|
+
const CHILDREN = 'Foo';
|
|
91
|
+
|
|
92
|
+
render(
|
|
93
|
+
<SiteFooter.Org data-testid="sitefooterorg" title="The Scottish Government" href="https://www.gov.scot/">
|
|
94
|
+
{CHILDREN}
|
|
95
|
+
</SiteFooter.Org>
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const siteFooterOrgContainer = screen.getByTestId('sitefooterorg');
|
|
99
|
+
const siteFooterOrgLink = within(siteFooterOrgContainer).getByRole('link');
|
|
100
|
+
|
|
101
|
+
expect(siteFooterOrgContainer).toHaveClass('ds_site-footer__org');
|
|
102
|
+
expect(siteFooterOrgContainer.tagName).toEqual('DIV');
|
|
103
|
+
|
|
104
|
+
expect(siteFooterOrgLink).toHaveClass('ds_site-footer__org-link');
|
|
105
|
+
expect(siteFooterOrgLink.tagName).toEqual('A');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('site footer org with image renders correctly', () => {
|
|
109
|
+
const CHILDREN = <img src="foo" alt="Foo" />
|
|
110
|
+
|
|
111
|
+
render(
|
|
112
|
+
<SiteFooter.Org data-testid="sitefooterorg" title="The Scottish Government" href="https://www.gov.scot/">
|
|
113
|
+
{CHILDREN}
|
|
114
|
+
</SiteFooter.Org>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const siteFooterOrgContainer = screen.getByTestId('sitefooterorg');
|
|
118
|
+
const siteFooterOrgImage = within(siteFooterOrgContainer).getByRole('img');
|
|
119
|
+
|
|
120
|
+
expect(siteFooterOrgImage).toHaveClass('ds_site-footer__org-logo');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('site footer license renders correctly', () => {
|
|
124
|
+
const CHILDREN = 'Hello';
|
|
125
|
+
|
|
126
|
+
render(
|
|
127
|
+
<SiteFooter.License data-testid="sitefooterlicense">
|
|
128
|
+
{CHILDREN}
|
|
129
|
+
</SiteFooter.License>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const siteFooterLicenseContainer = screen.getByTestId('sitefooterlicense');
|
|
133
|
+
|
|
134
|
+
expect(siteFooterLicenseContainer.innerHTML).toEqual(CHILDREN);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('passing additional props', () => {
|
|
138
|
+
render(
|
|
139
|
+
<SiteFooter data-testid="sitefooter" data-test="foo" />
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const siteFooter = screen.getByTestId('sitefooter');
|
|
143
|
+
expect(siteFooter?.dataset.test).toEqual('foo');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('passing additional CSS classes', () => {
|
|
147
|
+
render(
|
|
148
|
+
<SiteFooter data-testid="sitefooter" className="foo" />
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const siteFooter = screen.getByTestId('sitefooter');
|
|
152
|
+
expect(siteFooter).toHaveClass('foo');
|
|
153
|
+
});
|