@scottish-government/designsystem-react 0.7.0 → 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/{aspect-box/aspect-box.jsx → Checkbox/CheckboxGroup.jsx} +14 -30
- 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
- package/dist/common/abstract-notification-banner.jsx +0 -63
- package/dist/common/conditional-wrapper.jsx +0 -8
- package/dist/common/file-icon.jsx +0 -51
- package/dist/common/hint-text.jsx +0 -9
- package/dist/common/icon.jsx +0 -57
- package/dist/common/screen-reader-text.jsx +0 -9
- package/dist/common/wrapper-tag.jsx +0 -11
- package/dist/components/accordion/accordion.jsx +0 -102
- package/dist/components/back-to-top/back-to-top.jsx +0 -27
- package/dist/components/breadcrumbs/breadcrumbs.jsx +0 -28
- package/dist/components/button/button.jsx +0 -30
- package/dist/components/checkbox/checkbox.jsx +0 -62
- package/dist/components/confirmation-message/confirmation-message.jsx +0 -24
- package/dist/components/contents-nav/contents-nav.jsx +0 -33
- package/dist/components/cookie-banner/cookie-banner.jsx +0 -21
- package/dist/components/date-picker/date-picker.jsx +0 -54
- package/dist/components/details/details.jsx +0 -17
- package/dist/components/error-message/error-message.jsx +0 -12
- package/dist/components/error-summary/error-summary.jsx +0 -27
- package/dist/components/file-download/file-download.jsx +0 -50
- package/dist/components/hide-this-page/hide-this-page.jsx +0 -71
- package/dist/components/inset-text/inset-text.jsx +0 -14
- package/dist/components/notification-banner/notification-banner.jsx +0 -26
- package/dist/components/notification-panel/notification-panel.jsx +0 -21
- package/dist/components/page-header/page-header.jsx +0 -15
- package/dist/components/page-metadata/page-metadata.jsx +0 -26
- package/dist/components/pagination/pagination.jsx +0 -97
- package/dist/components/phase-banner/phase-banner.jsx +0 -23
- package/dist/components/question/question.jsx +0 -22
- package/dist/components/radio-button/radio-button.jsx +0 -43
- package/dist/components/select/select.jsx +0 -52
- package/dist/components/sequential-navigation/sequential-navigation.jsx +0 -31
- package/dist/components/side-navigation/side-navigation.jsx +0 -52
- package/dist/components/site-header/site-header.jsx +0 -68
- package/dist/components/site-navigation/site-navigation.jsx +0 -22
- package/dist/components/site-search/site-search.jsx +0 -55
- package/dist/components/skip-links/skip-links.jsx +0 -21
- package/dist/components/summary-card/summary-card.jsx +0 -67
- package/dist/components/summary-list/summary-list.jsx +0 -75
- package/dist/components/table/table.jsx +0 -24
- package/dist/components/tabs/tabs.jsx +0 -99
- package/dist/components/tag/tag.jsx +0 -13
- package/dist/components/task-list/task-list.jsx +0 -95
- package/dist/components/text-input/text-input.jsx +0 -58
- package/dist/components/textarea/textarea.jsx +0 -54
- package/dist/components/warning-text/warning-text.jsx +0 -16
- package/dist/icons/ArrowUpward.jsx +0 -41
- package/dist/icons/CalendarToday.jsx +0 -41
- package/dist/icons/Cancel.jsx +0 -40
- package/dist/icons/CheckCircle.jsx +0 -41
- package/dist/icons/ChevronLeft.jsx +0 -41
- package/dist/icons/ChevronRight.jsx +0 -41
- package/dist/icons/Close.jsx +0 -41
- package/dist/icons/Description.jsx +0 -41
- package/dist/icons/DoubleChevronLeft.jsx +0 -40
- package/dist/icons/DoubleChevronRight.jsx +0 -40
- package/dist/icons/Error.jsx +0 -41
- package/dist/icons/ExpandLess.jsx +0 -41
- package/dist/icons/ExpandMore.jsx +0 -41
- package/dist/icons/List.jsx +0 -44
- package/dist/icons/Menu.jsx +0 -41
- package/dist/icons/PriorityHigh.jsx +0 -42
- package/dist/icons/Search.jsx +0 -41
- package/dist/icons/index.js +0 -40
|
@@ -1,21 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
import WrapperTag from "../../common/WrapperTag";
|
|
1
|
+
import React, { Children, useId } from 'react';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
.replace(/ +/g, "-");
|
|
8
|
-
}
|
|
3
|
+
import ActionLink from '../../common/ActionLink';
|
|
4
|
+
import ConditionalWrapper from '../../common/ConditionalWrapper';
|
|
5
|
+
import WrapperTag from "../../common/WrapperTag";
|
|
9
6
|
|
|
10
|
-
const SummaryCard
|
|
11
|
-
|
|
7
|
+
const SummaryCard = ({
|
|
8
|
+
children,
|
|
12
9
|
className,
|
|
13
10
|
headingLevel = 'h3',
|
|
14
|
-
items,
|
|
15
11
|
title,
|
|
16
12
|
...props
|
|
17
|
-
}) => {
|
|
18
|
-
|
|
13
|
+
}: SGDS.Component.SummaryCard) => {
|
|
14
|
+
let actions: any[] = [];
|
|
15
|
+
let remainingChildren: any[] = [];
|
|
16
|
+
|
|
17
|
+
const describedById = useId();
|
|
18
|
+
|
|
19
|
+
Children.forEach(children, (child: React.ReactNode) => {
|
|
20
|
+
const thisChild = child as React.ReactElement<SGDS.Common.ActionLink>;
|
|
21
|
+
if (thisChild && thisChild.type === ActionLink) {
|
|
22
|
+
actions.push(React.cloneElement(thisChild, { describedby: describedById }));
|
|
23
|
+
} else {
|
|
24
|
+
remainingChildren.push(thisChild);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
19
27
|
|
|
20
28
|
return (
|
|
21
29
|
<div
|
|
@@ -32,29 +40,32 @@ const SummaryCard: React.FC<SGDS.Component.SummaryCard> = ({
|
|
|
32
40
|
tagName={headingLevel}
|
|
33
41
|
>{title}</WrapperTag>
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
{actions &&
|
|
44
|
+
<ConditionalWrapper
|
|
45
|
+
condition={actions.length > 1}
|
|
46
|
+
wrapper={(children: React.JSX.Element) => <ul className="ds_summary-card__actions-list">{children}</ul>}
|
|
47
|
+
>
|
|
48
|
+
{actions && actions.map((action, index: number) => (
|
|
49
|
+
<ConditionalWrapper
|
|
50
|
+
condition={actions.length > 1}
|
|
51
|
+
wrapper={(children: React.JSX.Element) => <li className="ds_summary-card__actions-list-item">{children}</li>}
|
|
52
|
+
key={'action' + index}
|
|
53
|
+
>
|
|
54
|
+
{action}
|
|
55
|
+
</ConditionalWrapper>
|
|
56
|
+
))}
|
|
57
|
+
</ConditionalWrapper>
|
|
58
|
+
}
|
|
50
59
|
</div>
|
|
51
60
|
<div className="ds_summary-card__content">
|
|
52
|
-
|
|
61
|
+
{remainingChildren}
|
|
53
62
|
</div>
|
|
54
63
|
</div>
|
|
55
64
|
);
|
|
56
65
|
};
|
|
57
66
|
|
|
58
67
|
SummaryCard.displayName = 'SummaryCard';
|
|
68
|
+
SummaryCard.Action = ActionLink;
|
|
69
|
+
SummaryCard.Action.displayName = 'SummaryCard.Action';
|
|
59
70
|
|
|
60
71
|
export default SummaryCard;
|
|
@@ -1,69 +1,39 @@
|
|
|
1
1
|
import { test, expect, vi } from 'vitest';
|
|
2
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
import SummaryList
|
|
2
|
+
import { within, render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import SummaryList from './SummaryList';
|
|
4
4
|
|
|
5
5
|
const ONCLICK_FUNCTION = vi.fn();
|
|
6
|
+
const TITLE = 'Name';
|
|
7
|
+
const VALUE_1 = 'Jane Smith';
|
|
8
|
+
const VALUE_2 = 'Tony Brown';
|
|
6
9
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
actions: [
|
|
12
|
-
{
|
|
13
|
-
title: 'Change',
|
|
14
|
-
href: '#foo'
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
title: 'Delete',
|
|
18
|
-
onclick: ONCLICK_FUNCTION
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
title: 'Date of birth',
|
|
24
|
-
value: '13 April 2001',
|
|
25
|
-
actions: [
|
|
26
|
-
{
|
|
27
|
-
title: 'Change',
|
|
28
|
-
href: '#bar'
|
|
29
|
-
}
|
|
30
|
-
]
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
title: 'Address',
|
|
34
|
-
value: `Scottish Government\nSt Andrew's House\nRegent Road\nEdinburgh\nEH1 3DG`,
|
|
35
|
-
actions: [
|
|
36
|
-
{
|
|
37
|
-
title: 'Change',
|
|
38
|
-
href: '#baz'
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
title: 'Contact details',
|
|
44
|
-
value: [
|
|
45
|
-
'email@gov.scot',
|
|
46
|
-
'0123 456 7890',
|
|
47
|
-
]
|
|
48
|
-
}
|
|
49
|
-
];
|
|
10
|
+
const ACTION_HREF = "#foo"
|
|
11
|
+
const ACTION_ONCLICK = ONCLICK_FUNCTION;
|
|
12
|
+
const ACTION_TEXT = 'Name';
|
|
13
|
+
const DESCRIBEDBY_ID = 'q1-name';
|
|
50
14
|
|
|
51
15
|
test('summary list renders correctly', () => {
|
|
52
16
|
render(
|
|
53
|
-
<SummaryList
|
|
17
|
+
<SummaryList data-testid="summarylist">
|
|
18
|
+
<SummaryList.Item title="key">
|
|
19
|
+
<SummaryList.Value>value</SummaryList.Value>
|
|
20
|
+
<SummaryList.Value>value2</SummaryList.Value>
|
|
21
|
+
<SummaryList.Value>value3</SummaryList.Value>
|
|
22
|
+
<SummaryList.Action href="foo">foo</SummaryList.Action>
|
|
23
|
+
<SummaryList.Action onclick={() => true}>bar</SummaryList.Action>
|
|
24
|
+
</SummaryList.Item>
|
|
25
|
+
</SummaryList>
|
|
54
26
|
);
|
|
55
27
|
|
|
56
|
-
const summaryList = screen.
|
|
57
|
-
const summaryListItems = summaryList.children;
|
|
28
|
+
const summaryList = screen.getByTestId('summarylist');
|
|
58
29
|
|
|
59
30
|
expect(summaryList).toHaveClass('ds_summary-list');
|
|
60
31
|
expect(summaryList.tagName).toEqual('OL');
|
|
61
|
-
expect(summaryListItems.length).toEqual(SUMMARY_ITEMS.length);
|
|
62
32
|
});
|
|
63
33
|
|
|
64
34
|
test('summary list without border', () => {
|
|
65
35
|
render(
|
|
66
|
-
<SummaryList noBorder
|
|
36
|
+
<SummaryList noBorder/>
|
|
67
37
|
);
|
|
68
38
|
|
|
69
39
|
const summaryList = screen.getAllByRole('list')[0];
|
|
@@ -72,14 +42,11 @@ test('summary list without border', () => {
|
|
|
72
42
|
});
|
|
73
43
|
|
|
74
44
|
test('summary list item renders correctly', () => {
|
|
75
|
-
const DESCRIBEDBY_ID = 'q2-date-of-birth';
|
|
76
|
-
|
|
77
45
|
render(
|
|
78
|
-
<Item
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/>
|
|
46
|
+
<SummaryList.Item title={TITLE}>
|
|
47
|
+
<SummaryList.Value>{VALUE_1}</SummaryList.Value>
|
|
48
|
+
<SummaryList.Action></SummaryList.Action>
|
|
49
|
+
</SummaryList.Item>
|
|
83
50
|
);
|
|
84
51
|
|
|
85
52
|
const item = screen.getAllByRole('listitem')[0];
|
|
@@ -91,8 +58,7 @@ test('summary list item renders correctly', () => {
|
|
|
91
58
|
expect(item).toHaveClass('ds_summary-list__item');
|
|
92
59
|
|
|
93
60
|
expect(key?.tagName).toEqual('SPAN');
|
|
94
|
-
expect(key?.textContent).toEqual(
|
|
95
|
-
expect(key).toHaveAttribute('id', DESCRIBEDBY_ID);
|
|
61
|
+
expect(key?.textContent).toEqual(TITLE);
|
|
96
62
|
|
|
97
63
|
expect(value?.tagName).toEqual('SPAN');
|
|
98
64
|
|
|
@@ -101,16 +67,15 @@ test('summary list item renders correctly', () => {
|
|
|
101
67
|
|
|
102
68
|
expect(actions?.tagName).toEqual('DIV');
|
|
103
69
|
|
|
104
|
-
expect(actions?.querySelector('.ds_link')).toHaveAttribute('aria-describedby',
|
|
70
|
+
expect(actions?.querySelector('.ds_link')).toHaveAttribute('aria-describedby', key?.id);
|
|
105
71
|
});
|
|
106
72
|
|
|
107
73
|
test('summary list item with multiple values', () => {
|
|
108
74
|
render(
|
|
109
|
-
<Item
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
/>
|
|
75
|
+
<SummaryList.Item title={TITLE}>
|
|
76
|
+
<SummaryList.Value>{VALUE_1}</SummaryList.Value>
|
|
77
|
+
<SummaryList.Value>{VALUE_2}</SummaryList.Value>
|
|
78
|
+
</SummaryList.Item>
|
|
114
79
|
);
|
|
115
80
|
|
|
116
81
|
const item = screen.getAllByRole('listitem')[0];
|
|
@@ -121,30 +86,23 @@ test('summary list item with multiple values', () => {
|
|
|
121
86
|
expect(valueList).toHaveClass('ds_no-bullets');
|
|
122
87
|
expect(valueList?.tagName).toEqual('UL');
|
|
123
88
|
|
|
124
|
-
expect(valueListItems?.length).toEqual(SUMMARY_ITEMS[3].value.length);
|
|
125
|
-
|
|
126
89
|
expect(valueListItems[0].tagName).toEqual('LI');
|
|
127
|
-
expect(valueListItems[0].innerHTML).toEqual(`<q class="ds_summary-list__answer">${
|
|
90
|
+
expect(valueListItems[0].innerHTML).toEqual(`<q class="ds_summary-list__answer">${VALUE_1}</q>`);
|
|
128
91
|
});
|
|
129
92
|
|
|
130
93
|
test('summary list item with no value', () => {
|
|
131
94
|
render(
|
|
132
|
-
<Item
|
|
133
|
-
|
|
134
|
-
title={SUMMARY_ITEMS[3].title}
|
|
135
|
-
/>
|
|
95
|
+
<SummaryList.Item title={TITLE}>
|
|
96
|
+
</SummaryList.Item>
|
|
136
97
|
);
|
|
137
98
|
|
|
138
99
|
const item = screen.getAllByRole('listitem')[0];
|
|
139
100
|
const value = item.querySelector('.ds_summary-list__value');
|
|
140
|
-
const answer = value?.children[0];
|
|
141
101
|
|
|
142
|
-
expect(
|
|
102
|
+
expect(value?.textContent).toEqual('');
|
|
143
103
|
});
|
|
144
104
|
|
|
145
105
|
test('summary list item with multiple actions', () => {
|
|
146
|
-
const ITEM_TITLE = 'Name';
|
|
147
|
-
const ITEM_VALUE = 'Jane Smith';
|
|
148
106
|
const ITEM_ACTIONS = [
|
|
149
107
|
{
|
|
150
108
|
title: 'Change',
|
|
@@ -157,87 +115,30 @@ test('summary list item with multiple actions', () => {
|
|
|
157
115
|
];
|
|
158
116
|
|
|
159
117
|
render(
|
|
160
|
-
<Item
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
118
|
+
<SummaryList.Item title={TITLE}>
|
|
119
|
+
<SummaryList.Value>{VALUE_1}</SummaryList.Value>
|
|
120
|
+
<SummaryList.Action href={ITEM_ACTIONS[0].href}>{ITEM_ACTIONS[0].title}</SummaryList.Action>
|
|
121
|
+
<SummaryList.Action onclick={ITEM_ACTIONS[0].onclick}>{ITEM_ACTIONS[1].title}</SummaryList.Action>
|
|
122
|
+
</SummaryList.Item>
|
|
165
123
|
);
|
|
166
124
|
|
|
167
125
|
const item = screen.getAllByRole('listitem')[0];
|
|
168
126
|
const actionsElement = item.querySelector('.ds_summary-list__actions');
|
|
127
|
+
const actionsList = within(actionsElement as HTMLElement).getByRole('list')
|
|
169
128
|
|
|
170
|
-
expect(
|
|
171
|
-
expect(
|
|
172
|
-
expect(actionsElement?.children[1].textContent).toEqual(ITEM_ACTIONS[1].title);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
test('button action', () => {
|
|
176
|
-
const DESCRIBEDBY_ID = 'q1-name';
|
|
177
|
-
const ACTION_TITLE = 'Name';
|
|
178
|
-
const ACTION_ONCLICK = ONCLICK_FUNCTION;
|
|
179
|
-
|
|
180
|
-
render(
|
|
181
|
-
<Action
|
|
182
|
-
describedby={DESCRIBEDBY_ID}
|
|
183
|
-
href={undefined}
|
|
184
|
-
onclick={ACTION_ONCLICK}
|
|
185
|
-
title={ACTION_TITLE}
|
|
186
|
-
/>
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
const action = screen.getByRole('button');
|
|
190
|
-
|
|
191
|
-
expect(action).toHaveClass('ds_link');
|
|
192
|
-
expect(action).toHaveAttribute('aria-describedby', DESCRIBEDBY_ID);
|
|
193
|
-
expect(action).toHaveAttribute('type', 'button');
|
|
194
|
-
expect(action).not.toHaveAttribute('href');
|
|
195
|
-
expect(action.tagName).toEqual('BUTTON');
|
|
196
|
-
expect(action.textContent).toEqual(ACTION_TITLE);
|
|
197
|
-
|
|
198
|
-
fireEvent.click(action);
|
|
199
|
-
|
|
200
|
-
expect(ONCLICK_FUNCTION).toHaveBeenCalled();
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
test('link action', () => {
|
|
204
|
-
const DESCRIBEDBY_ID = 'q1-name';
|
|
205
|
-
const ACTION_TITLE = 'Name';
|
|
206
|
-
const ACTION_HREF = "#foo"
|
|
207
|
-
const ACTION_ONCLICK = ONCLICK_FUNCTION;
|
|
208
|
-
|
|
209
|
-
render(
|
|
210
|
-
<Action
|
|
211
|
-
describedby={DESCRIBEDBY_ID}
|
|
212
|
-
href={ACTION_HREF}
|
|
213
|
-
onclick={ACTION_ONCLICK}
|
|
214
|
-
title={ACTION_TITLE}
|
|
215
|
-
/>
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
const action = screen.getByRole('link');
|
|
219
|
-
|
|
220
|
-
expect(action).toHaveClass('ds_link');
|
|
221
|
-
expect(action).toHaveAttribute('aria-describedby', DESCRIBEDBY_ID);
|
|
222
|
-
expect(action).toHaveAttribute('href', ACTION_HREF);
|
|
223
|
-
expect(action).not.toHaveAttribute('type');
|
|
224
|
-
expect(action.tagName).toEqual('A');
|
|
225
|
-
expect(action.textContent).toEqual(ACTION_TITLE);
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
test('multiline answer', () => {
|
|
229
|
-
render(
|
|
230
|
-
<Answer value={SUMMARY_ITEMS[2].value} />
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
const answer = document.querySelector('.ds_summary-list__answer');
|
|
129
|
+
expect(actionsList).toHaveClass('ds_summary-list__actions-list');
|
|
130
|
+
expect(actionsList.tagName).toEqual('UL');
|
|
234
131
|
|
|
235
|
-
expect(
|
|
132
|
+
expect(actionsList?.children.length).toEqual(2);
|
|
133
|
+
expect(actionsList?.children[0]).toHaveClass('ds_summary-list__actions-list-item');
|
|
134
|
+
expect(actionsList?.children[0].tagName).toEqual('LI');
|
|
135
|
+
expect(actionsList?.children[0].textContent).toEqual(ITEM_ACTIONS[0].title);
|
|
136
|
+
expect(actionsList?.children[1].textContent).toEqual(ITEM_ACTIONS[1].title);
|
|
236
137
|
});
|
|
237
138
|
|
|
238
139
|
test('passing additional props', () => {
|
|
239
140
|
render(
|
|
240
|
-
<SummaryList data-test="foo"
|
|
141
|
+
<SummaryList data-test="foo" />
|
|
241
142
|
);
|
|
242
143
|
|
|
243
144
|
const summaryList = screen.getAllByRole('list')[0];
|
|
@@ -246,7 +147,7 @@ test('passing additional props', () => {
|
|
|
246
147
|
|
|
247
148
|
test('passing additional CSS classes', () => {
|
|
248
149
|
render(
|
|
249
|
-
<SummaryList className="foo"
|
|
150
|
+
<SummaryList className="foo" />
|
|
250
151
|
);
|
|
251
152
|
|
|
252
153
|
const summaryList = screen.getAllByRole('list')[0];
|
|
@@ -1,71 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
import WrapperTag from '../../common/WrapperTag';
|
|
3
|
-
|
|
4
|
-
function escapedNewLineToLineBreakTag (string: string) {
|
|
5
|
-
if (typeof string === 'string') {
|
|
6
|
-
// @ts-ignore
|
|
7
|
-
return string.split('\n').map((item, index) => {
|
|
8
|
-
return (index === 0) ? item : [<br key={index} />, item]
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function convertToSlug(string: string) {
|
|
14
|
-
return string.toLowerCase()
|
|
15
|
-
.replace(/[^\w ]+/g, "")
|
|
16
|
-
.replace(/ +/g, "-");
|
|
17
|
-
}
|
|
1
|
+
import React, { Children, useId } from 'react';
|
|
18
2
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}) => {
|
|
22
|
-
const processedValue = escapedNewLineToLineBreakTag(value.toString());
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<q className="ds_summary-list__answer">{processedValue}</q>
|
|
26
|
-
);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const Action: React.FC<SGDS.Component.SummaryList.Action> = ({
|
|
30
|
-
describedby,
|
|
31
|
-
href,
|
|
32
|
-
onclick,
|
|
33
|
-
title,
|
|
34
|
-
}) => {
|
|
35
|
-
let tagName = 'button';
|
|
36
|
-
if (href) {
|
|
37
|
-
tagName = 'a';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<WrapperTag
|
|
42
|
-
aria-describedby={describedby}
|
|
43
|
-
className="ds_link"
|
|
44
|
-
href={href}
|
|
45
|
-
onClick={onclick}
|
|
46
|
-
tagName={tagName}
|
|
47
|
-
type={tagName === 'button' ? 'button' : undefined}
|
|
48
|
-
>
|
|
49
|
-
{title}
|
|
50
|
-
</WrapperTag>
|
|
51
|
-
);
|
|
52
|
-
};
|
|
3
|
+
import ActionLink from '../../common/ActionLink';
|
|
4
|
+
import ConditionalWrapper from '../../common/ConditionalWrapper';
|
|
53
5
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
let values: string[] = [];
|
|
6
|
+
const Item = ({
|
|
7
|
+
children,
|
|
8
|
+
title
|
|
9
|
+
}: SGDS.Component.SummaryList.Item) => {
|
|
10
|
+
let values: any[] = [];
|
|
11
|
+
let actions: any[] = [];
|
|
61
12
|
|
|
62
|
-
|
|
63
|
-
values = value;
|
|
64
|
-
} else {
|
|
65
|
-
values = [value || ''];
|
|
66
|
-
}
|
|
13
|
+
const describedById = useId();
|
|
67
14
|
|
|
68
|
-
|
|
15
|
+
Children.forEach(children, (child: React.ReactNode) => {
|
|
16
|
+
const thisChild = child as React.ReactElement<SGDS.Common.ActionLink>;
|
|
17
|
+
if (thisChild && thisChild.type === Value) {
|
|
18
|
+
values.push(thisChild);
|
|
19
|
+
} else if (thisChild && thisChild.type === ActionLink) {
|
|
20
|
+
actions.push(React.cloneElement(thisChild, { describedby: describedById }));
|
|
21
|
+
}
|
|
22
|
+
});
|
|
69
23
|
|
|
70
24
|
return (
|
|
71
25
|
<li className="ds_summary-list__item">
|
|
@@ -75,42 +29,53 @@ export const Item: React.FC<SGDS.Component.SummaryList.Item> = ({
|
|
|
75
29
|
condition={values.length > 1}
|
|
76
30
|
wrapper={(children: React.JSX.Element) => <ul className="ds_no-bullets">{children}</ul>}
|
|
77
31
|
>
|
|
78
|
-
|
|
32
|
+
{values && values.map((value, index: number) => (
|
|
79
33
|
<ConditionalWrapper
|
|
80
34
|
condition={values.length > 1}
|
|
81
35
|
wrapper={(children: React.JSX.Element) => <li>{children}</li>}
|
|
82
36
|
key={'answer' + index}
|
|
83
37
|
>
|
|
84
|
-
|
|
85
|
-
value={value}
|
|
86
|
-
/>
|
|
38
|
+
{value}
|
|
87
39
|
</ConditionalWrapper>
|
|
88
40
|
))}
|
|
89
41
|
</ConditionalWrapper>
|
|
90
42
|
</span>
|
|
91
43
|
{actions &&
|
|
92
44
|
<div className="ds_summary-list__actions">
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
45
|
+
<ConditionalWrapper
|
|
46
|
+
condition={actions.length > 1}
|
|
47
|
+
wrapper={(children: React.JSX.Element) => <ul className="ds_summary-list__actions-list">{children}</ul>}
|
|
48
|
+
>
|
|
49
|
+
{actions && actions.map((action, index: number) => (
|
|
50
|
+
<ConditionalWrapper
|
|
51
|
+
condition={actions.length > 1}
|
|
52
|
+
wrapper={(children: React.JSX.Element) => <li className="ds_summary-list__actions-list-item">{children}</li>}
|
|
53
|
+
key={'action' + index}
|
|
54
|
+
>
|
|
55
|
+
{action}
|
|
56
|
+
</ConditionalWrapper>
|
|
57
|
+
))}
|
|
58
|
+
</ConditionalWrapper>
|
|
102
59
|
</div>
|
|
103
60
|
}
|
|
104
61
|
</li>
|
|
105
62
|
);
|
|
106
63
|
};
|
|
107
64
|
|
|
108
|
-
const
|
|
65
|
+
const Value = ({
|
|
66
|
+
children
|
|
67
|
+
}: SGDS.Component.SummaryList.Answer) => {
|
|
68
|
+
return (
|
|
69
|
+
<q className="ds_summary-list__answer">{children}</q>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const SummaryList = ({
|
|
74
|
+
children,
|
|
109
75
|
className,
|
|
110
|
-
items,
|
|
111
76
|
noBorder,
|
|
112
77
|
...props
|
|
113
|
-
}) => {
|
|
78
|
+
}: SGDS.Component.SummaryList) => {
|
|
114
79
|
return (
|
|
115
80
|
<ol
|
|
116
81
|
className={[
|
|
@@ -120,22 +85,19 @@ const SummaryList: React.FC<SGDS.Component.SummaryList> = ({
|
|
|
120
85
|
].join(' ')}
|
|
121
86
|
{...props}
|
|
122
87
|
>
|
|
123
|
-
|
|
124
|
-
<Item
|
|
125
|
-
actions={item.actions}
|
|
126
|
-
title={item.title}
|
|
127
|
-
value={item.value}
|
|
128
|
-
index={index}
|
|
129
|
-
key={'summarylistitem' + index}
|
|
130
|
-
/>
|
|
131
|
-
))}
|
|
88
|
+
{children}
|
|
132
89
|
</ol>
|
|
133
90
|
);
|
|
134
91
|
};
|
|
135
92
|
|
|
93
|
+
|
|
94
|
+
SummaryList.Action = ActionLink;
|
|
95
|
+
SummaryList.Item = Item;
|
|
96
|
+
SummaryList.Value = Value;
|
|
97
|
+
|
|
136
98
|
SummaryList.displayName = 'SummaryList';
|
|
137
|
-
Action.displayName = '
|
|
138
|
-
|
|
139
|
-
|
|
99
|
+
SummaryList.Action.displayName = 'SummaryList.Action';
|
|
100
|
+
Item.displayName = 'SummaryList.Item';
|
|
101
|
+
Value.displayName = 'SumaryList.Value';
|
|
140
102
|
|
|
141
103
|
export default SummaryList;
|
|
@@ -2,12 +2,12 @@ import { useEffect, useRef } from 'react';
|
|
|
2
2
|
// @ts-ignore
|
|
3
3
|
import DSTable from '@scottish-government/design-system/src/components/table/table';
|
|
4
4
|
|
|
5
|
-
const Table
|
|
5
|
+
const Table = ({
|
|
6
6
|
children,
|
|
7
7
|
className,
|
|
8
8
|
smallscreen,
|
|
9
9
|
...props
|
|
10
|
-
}) => {
|
|
10
|
+
}: SGDS.Component.Table) => {
|
|
11
11
|
const ref = useRef(null);
|
|
12
12
|
|
|
13
13
|
useEffect(() => {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { Children, useEffect, useRef } from 'react';
|
|
2
2
|
import WrapperTag from '../../common/WrapperTag';
|
|
3
3
|
// @ts-ignore
|
|
4
4
|
import DSTabs from '@scottish-government/design-system/src/components/tabs/tabs';
|
|
5
5
|
import slugify from '../../utils/slugify';
|
|
6
6
|
|
|
7
|
-
const TabItem
|
|
7
|
+
const TabItem = ({
|
|
8
8
|
bordered,
|
|
9
9
|
children,
|
|
10
10
|
className,
|
|
11
11
|
id,
|
|
12
12
|
tabLabel,
|
|
13
13
|
...props
|
|
14
|
-
}) => {
|
|
14
|
+
}: SGDS.Component.Tabs.Item) => {
|
|
15
15
|
return (
|
|
16
16
|
<div
|
|
17
17
|
className={[
|
|
@@ -27,19 +27,18 @@ const TabItem: React.FC<SGDS.Component.Tabs.Item> = ({
|
|
|
27
27
|
);
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
const TabListItem
|
|
31
|
-
|
|
30
|
+
const TabListItem = ({
|
|
31
|
+
children,
|
|
32
32
|
href
|
|
33
|
-
}) => {
|
|
33
|
+
}: SGDS.Component.Tabs.TabListItem) => {
|
|
34
34
|
return (
|
|
35
35
|
<li className="ds_tabs__tab">
|
|
36
|
-
<a className="ds_tabs__tab-link" href={href}>{
|
|
36
|
+
<a className="ds_tabs__tab-link" href={href}>{children}</a>
|
|
37
37
|
</li>
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const Tabs
|
|
42
|
-
& { Item: React.FC<SGDS.Component.Tabs.Item> } = ({
|
|
41
|
+
const Tabs = ({
|
|
43
42
|
baseId = 'tabs',
|
|
44
43
|
bordered = true,
|
|
45
44
|
children,
|
|
@@ -48,7 +47,7 @@ const Tabs: React.FC<SGDS.Component.Tabs>
|
|
|
48
47
|
manual = false,
|
|
49
48
|
title = 'Contents',
|
|
50
49
|
...props
|
|
51
|
-
}) => {
|
|
50
|
+
}: SGDS.Component.Tabs) => {
|
|
52
51
|
const ref = useRef(null);
|
|
53
52
|
|
|
54
53
|
const headingId = `${baseId}-heading`;
|
|
@@ -60,10 +59,10 @@ const Tabs: React.FC<SGDS.Component.Tabs>
|
|
|
60
59
|
}, [ref]);
|
|
61
60
|
|
|
62
61
|
const processedItems = Children.map(children, child => {
|
|
63
|
-
|
|
64
|
-
let thisChild = child as React.ReactElement<SGDS.Component.Tabs.Item>;
|
|
62
|
+
const thisChild = child as React.ReactElement<SGDS.Component.Tabs.Item>;
|
|
65
63
|
|
|
66
|
-
|
|
64
|
+
if (thisChild && thisChild.type === TabItem) {
|
|
65
|
+
return React.cloneElement(thisChild, {
|
|
67
66
|
bordered: bordered,
|
|
68
67
|
id: thisChild.props.id || `${baseId}-${slugify(thisChild.props.tabLabel)}`,
|
|
69
68
|
});
|
|
@@ -71,8 +70,8 @@ const Tabs: React.FC<SGDS.Component.Tabs>
|
|
|
71
70
|
});
|
|
72
71
|
|
|
73
72
|
const tabListItems = Children.map(processedItems, child => {
|
|
74
|
-
if (
|
|
75
|
-
return
|
|
73
|
+
if (child && child.type === TabItem) {
|
|
74
|
+
return <TabListItem href={`#${child.props.id}`}>{child.props.tabLabel}</TabListItem>
|
|
76
75
|
}
|
|
77
76
|
});
|
|
78
77
|
|