@scottish-government/designsystem-react 0.7.0 → 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.
Files changed (203) hide show
  1. package/@types/common/AbstractNotificationBanner.d.ts +2 -2
  2. package/@types/common/ActionLink.d.ts +8 -0
  3. package/@types/common/FileIcon.d.ts +1 -1
  4. package/@types/common/Icon.d.ts +1 -1
  5. package/@types/components/Breadcrumbs.d.ts +2 -5
  6. package/@types/components/Checkbox.d.ts +0 -2
  7. package/@types/components/ConfirmationMessage.d.ts +1 -1
  8. package/@types/components/ContentsNav.d.ts +4 -6
  9. package/@types/components/DatePicker.d.ts +1 -1
  10. package/@types/components/ErrorSummary.d.ts +3 -4
  11. package/@types/components/NotificationPanel.d.ts +1 -1
  12. package/@types/components/Pagination.d.ts +5 -4
  13. package/@types/components/PhaseBanner.d.ts +0 -1
  14. package/@types/components/Question.d.ts +1 -1
  15. package/@types/components/RadioButton.d.ts +0 -1
  16. package/@types/components/Select.d.ts +0 -7
  17. package/@types/components/SequentialNavigation.d.ts +4 -4
  18. package/@types/components/SideNavigation.d.ts +4 -5
  19. package/@types/components/SiteFooter.d.ts +25 -0
  20. package/@types/components/SiteHeader.d.ts +10 -3
  21. package/@types/components/SiteNavigation.d.ts +2 -3
  22. package/@types/components/SkipLinks.d.ts +3 -4
  23. package/@types/components/SummaryCard.d.ts +0 -2
  24. package/@types/components/SummaryList.d.ts +0 -13
  25. package/@types/components/Tabs.d.ts +0 -1
  26. package/@types/components/Tag.d.ts +1 -3
  27. package/@types/components/TaskList.d.ts +1 -0
  28. package/@types/sgds.d.ts +13 -2
  29. package/CHANGELOG.md +63 -1
  30. package/dist/common/AbstractNotificationBanner.jsx +8 -6
  31. package/dist/common/ActionLink.jsx +19 -0
  32. package/dist/common/FileIcon.jsx +2 -7
  33. package/dist/common/Icon.jsx +3 -9
  34. package/dist/components/Accordion/Accordion.jsx +2 -2
  35. package/dist/components/Breadcrumbs/Breadcrumbs.jsx +20 -15
  36. package/dist/components/Checkbox/Checkbox.jsx +2 -30
  37. package/dist/components/{aspect-box/aspect-box.jsx → Checkbox/CheckboxGroup.jsx} +19 -29
  38. package/dist/components/ContentsNav/ContentsNav.jsx +27 -16
  39. package/dist/components/CookieBanner/CookieBanner.jsx +1 -0
  40. package/dist/components/DatePicker/DatePicker.jsx +5 -5
  41. package/dist/components/ErrorSummary/ErrorSummary.jsx +28 -18
  42. package/dist/components/NotificationBanner/NotificationBanner.jsx +2 -2
  43. package/dist/components/Pagination/Pagination.jsx +42 -22
  44. package/dist/components/PhaseBanner/PhaseBanner.jsx +3 -3
  45. package/dist/components/Question/Question.jsx +3 -3
  46. package/dist/components/RadioButton/RadioButton.jsx +3 -17
  47. package/dist/{common/icon.jsx → components/RadioButton/RadioGroup.jsx} +22 -18
  48. package/dist/components/Select/Select.jsx +4 -7
  49. package/dist/components/SequentialNavigation/SequentialNavigation.jsx +31 -18
  50. package/dist/components/SideNavigation/SideNavigation.jsx +17 -16
  51. package/dist/components/SiteFooter/SiteFooter.jsx +104 -0
  52. package/dist/components/SiteHeader/SiteHeader.jsx +113 -32
  53. package/dist/components/SiteNavigation/SiteNavigation.jsx +20 -7
  54. package/dist/components/SkipLinks/SkipLinks.jsx +10 -10
  55. package/dist/components/SummaryCard/SummaryCard.jsx +25 -14
  56. package/dist/components/SummaryList/SummaryList.jsx +65 -47
  57. package/dist/components/Tabs/Tabs.jsx +6 -6
  58. package/dist/components/Tag/Tag.jsx +2 -2
  59. package/dist/components/TaskList/TaskList.jsx +14 -3
  60. package/dist/components/TextInput/TextInput.jsx +3 -3
  61. package/dist/components/Textarea/Textarea.jsx +3 -3
  62. package/dist/tsconfig.tsbuildinfo +1 -1
  63. package/package.json +1 -1
  64. package/src/common/AbstractNotificationBanner.test.tsx +1 -1
  65. package/src/common/AbstractNotificationBanner.tsx +14 -13
  66. package/src/common/ActionLink.test.tsx +80 -0
  67. package/src/common/ActionLink.tsx +27 -0
  68. package/src/common/ConditionalWrapper.tsx +1 -1
  69. package/src/common/FileIcon.tsx +7 -11
  70. package/src/common/HintText.tsx +2 -2
  71. package/src/common/Icon.tsx +13 -17
  72. package/src/common/ScreenReaderText.tsx +2 -2
  73. package/src/common/WrapperTag.tsx +2 -2
  74. package/src/components/Accordion/Accordion.test.tsx +1 -1
  75. package/src/components/Accordion/Accordion.tsx +6 -7
  76. package/src/components/AspectBox/AspectBox.tsx +2 -2
  77. package/src/components/BackToTop/BackToTop.tsx +2 -2
  78. package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +79 -47
  79. package/src/components/Breadcrumbs/Breadcrumbs.tsx +31 -31
  80. package/src/components/Button/Button.tsx +2 -2
  81. package/src/components/Checkbox/Checkbox.test.tsx +1 -96
  82. package/src/components/Checkbox/Checkbox.tsx +3 -55
  83. package/src/components/Checkbox/CheckboxGroup.test.tsx +37 -0
  84. package/src/components/Checkbox/CheckboxGroup.tsx +46 -0
  85. package/src/components/ConfirmationMessage/ConfirmationMessage.tsx +2 -2
  86. package/src/components/ContentsNav/ContentsNav.test.tsx +40 -51
  87. package/src/components/ContentsNav/ContentsNav.tsx +32 -25
  88. package/src/components/CookieBanner/CookieBanner.tsx +3 -3
  89. package/src/components/DatePicker/DatePicker.test.tsx +1 -1
  90. package/src/components/DatePicker/DatePicker.tsx +7 -7
  91. package/src/components/Details/Details.tsx +2 -2
  92. package/src/components/ErrorMessage/ErrorMessage.tsx +2 -2
  93. package/src/components/ErrorSummary/ErrorSummary.test.tsx +40 -34
  94. package/src/components/ErrorSummary/ErrorSummary.tsx +40 -32
  95. package/src/components/FileDownload/FileDownload.tsx +2 -2
  96. package/src/components/HideThisPage/HideThisPage.tsx +2 -2
  97. package/src/components/InsetText/InsetText.tsx +2 -2
  98. package/src/components/NotificationBanner/NotificationBanner.tsx +6 -7
  99. package/src/components/NotificationPanel/NotificationPanel.tsx +2 -2
  100. package/src/components/PageHeader/PageHeader.tsx +2 -2
  101. package/src/components/PageMetadata/PageMetadata.tsx +4 -5
  102. package/src/components/Pagination/Pagination.test.tsx +26 -7
  103. package/src/components/Pagination/Pagination.tsx +70 -36
  104. package/src/components/PhaseBanner/PhaseBanner.tsx +4 -5
  105. package/src/components/Question/Question.test.tsx +1 -1
  106. package/src/components/Question/Question.tsx +5 -5
  107. package/src/components/RadioButton/RadioButton.test.tsx +7 -126
  108. package/src/components/RadioButton/RadioButton.tsx +4 -41
  109. package/src/components/RadioButton/RadioGroup.test.tsx +65 -0
  110. package/src/components/RadioButton/RadioGroup.tsx +38 -0
  111. package/src/components/Select/Select.test.tsx +39 -37
  112. package/src/components/Select/Select.tsx +7 -22
  113. package/src/components/SequentialNavigation/SequentialNavigation.test.tsx +32 -21
  114. package/src/components/SequentialNavigation/SequentialNavigation.tsx +52 -30
  115. package/src/components/SideNavigation/SideNavigation.test.tsx +39 -85
  116. package/src/components/SideNavigation/SideNavigation.tsx +27 -29
  117. package/src/components/SiteFooter/SiteFooter.test.tsx +153 -0
  118. package/src/components/SiteFooter/SiteFooter.tsx +107 -0
  119. package/src/components/SiteHeader/SiteHeader.test.tsx +87 -79
  120. package/src/components/SiteHeader/SiteHeader.tsx +103 -40
  121. package/src/components/SiteNavigation/SiteNavigation.test.tsx +42 -23
  122. package/src/components/SiteNavigation/SiteNavigation.tsx +28 -16
  123. package/src/components/SiteSearch/SiteSearch.tsx +2 -2
  124. package/src/components/SkipLinks/SkipLinks.test.tsx +22 -10
  125. package/src/components/SkipLinks/SkipLinks.tsx +16 -15
  126. package/src/components/SummaryCard/SummaryCard.test.tsx +31 -35
  127. package/src/components/SummaryCard/SummaryCard.tsx +39 -28
  128. package/src/components/SummaryList/SummaryList.test.tsx +49 -148
  129. package/src/components/SummaryList/SummaryList.tsx +54 -92
  130. package/src/components/Table/Table.tsx +2 -2
  131. package/src/components/Tabs/Tabs.tsx +14 -15
  132. package/src/components/Tag/Tag.test.tsx +4 -4
  133. package/src/components/Tag/Tag.tsx +4 -4
  134. package/src/components/TaskList/TaskList.test.tsx +26 -0
  135. package/src/components/TaskList/TaskList.tsx +21 -11
  136. package/src/components/TextInput/TextInput.test.tsx +1 -1
  137. package/src/components/TextInput/TextInput.tsx +5 -5
  138. package/src/components/Textarea/Textarea.test.tsx +1 -1
  139. package/src/components/Textarea/Textarea.tsx +5 -5
  140. package/src/components/WarningText/WarningText.tsx +2 -2
  141. package/dist/common/abstract-notification-banner.jsx +0 -63
  142. package/dist/common/conditional-wrapper.jsx +0 -8
  143. package/dist/common/file-icon.jsx +0 -51
  144. package/dist/common/hint-text.jsx +0 -9
  145. package/dist/common/screen-reader-text.jsx +0 -9
  146. package/dist/common/wrapper-tag.jsx +0 -11
  147. package/dist/components/accordion/accordion.jsx +0 -102
  148. package/dist/components/back-to-top/back-to-top.jsx +0 -27
  149. package/dist/components/breadcrumbs/breadcrumbs.jsx +0 -28
  150. package/dist/components/button/button.jsx +0 -30
  151. package/dist/components/checkbox/checkbox.jsx +0 -62
  152. package/dist/components/confirmation-message/confirmation-message.jsx +0 -24
  153. package/dist/components/contents-nav/contents-nav.jsx +0 -33
  154. package/dist/components/cookie-banner/cookie-banner.jsx +0 -21
  155. package/dist/components/date-picker/date-picker.jsx +0 -54
  156. package/dist/components/details/details.jsx +0 -17
  157. package/dist/components/error-message/error-message.jsx +0 -12
  158. package/dist/components/error-summary/error-summary.jsx +0 -27
  159. package/dist/components/file-download/file-download.jsx +0 -50
  160. package/dist/components/hide-this-page/hide-this-page.jsx +0 -71
  161. package/dist/components/inset-text/inset-text.jsx +0 -14
  162. package/dist/components/notification-banner/notification-banner.jsx +0 -26
  163. package/dist/components/notification-panel/notification-panel.jsx +0 -21
  164. package/dist/components/page-header/page-header.jsx +0 -15
  165. package/dist/components/page-metadata/page-metadata.jsx +0 -26
  166. package/dist/components/pagination/pagination.jsx +0 -97
  167. package/dist/components/phase-banner/phase-banner.jsx +0 -23
  168. package/dist/components/question/question.jsx +0 -22
  169. package/dist/components/radio-button/radio-button.jsx +0 -43
  170. package/dist/components/select/select.jsx +0 -52
  171. package/dist/components/sequential-navigation/sequential-navigation.jsx +0 -31
  172. package/dist/components/side-navigation/side-navigation.jsx +0 -52
  173. package/dist/components/site-header/site-header.jsx +0 -68
  174. package/dist/components/site-navigation/site-navigation.jsx +0 -22
  175. package/dist/components/site-search/site-search.jsx +0 -55
  176. package/dist/components/skip-links/skip-links.jsx +0 -21
  177. package/dist/components/summary-card/summary-card.jsx +0 -67
  178. package/dist/components/summary-list/summary-list.jsx +0 -75
  179. package/dist/components/table/table.jsx +0 -24
  180. package/dist/components/tabs/tabs.jsx +0 -99
  181. package/dist/components/tag/tag.jsx +0 -13
  182. package/dist/components/task-list/task-list.jsx +0 -95
  183. package/dist/components/text-input/text-input.jsx +0 -58
  184. package/dist/components/textarea/textarea.jsx +0 -54
  185. package/dist/components/warning-text/warning-text.jsx +0 -16
  186. package/dist/icons/ArrowUpward.jsx +0 -41
  187. package/dist/icons/CalendarToday.jsx +0 -41
  188. package/dist/icons/Cancel.jsx +0 -40
  189. package/dist/icons/CheckCircle.jsx +0 -41
  190. package/dist/icons/ChevronLeft.jsx +0 -41
  191. package/dist/icons/ChevronRight.jsx +0 -41
  192. package/dist/icons/Close.jsx +0 -41
  193. package/dist/icons/Description.jsx +0 -41
  194. package/dist/icons/DoubleChevronLeft.jsx +0 -40
  195. package/dist/icons/DoubleChevronRight.jsx +0 -40
  196. package/dist/icons/Error.jsx +0 -41
  197. package/dist/icons/ExpandLess.jsx +0 -41
  198. package/dist/icons/ExpandMore.jsx +0 -41
  199. package/dist/icons/List.jsx +0 -44
  200. package/dist/icons/Menu.jsx +0 -41
  201. package/dist/icons/PriorityHigh.jsx +0 -42
  202. package/dist/icons/Search.jsx +0 -41
  203. package/dist/icons/index.js +0 -40
@@ -2,24 +2,17 @@ import { test, expect } from 'vitest';
2
2
  import { render, screen, within } from '@testing-library/react';
3
3
  import ErrorSummary from './ErrorSummary';
4
4
 
5
- const ERRORS = [
6
- { fragmentId: 'did-resolve', title: 'Did this resolve your issue?' },
7
- { fragmentId: 'what-topics', title: 'What topics are you interested in?' },
8
- { fragmentId: 'more-detail', title: 'Please provide more detail' }
9
- ];
5
+ const ERROR_FRAGMENT_ID = 'did-resolve';
6
+ const ERROR_TEXT = 'Did this resolve your issue?';
10
7
 
11
8
  test('error summary renders correctly', () => {
12
- const TITLE_ID = 'error-summary-title';
13
-
14
9
  render(
15
- <ErrorSummary data-testid="errorsummary" errors={ERRORS} />
10
+ <ErrorSummary data-testid="errorsummary"/>
16
11
  );
17
12
 
18
13
  const errorSummaryElement = screen.getByTestId('errorsummary');
19
14
  const errorSummaryTitle = within(errorSummaryElement).getByRole('heading');
20
15
  const errorSummaryList = within(errorSummaryElement).getByRole('list');
21
- const errorSummaryItems = within(errorSummaryList).getAllByRole('listitem');
22
- const errorSummaryLink1 = within(errorSummaryItems[0]).getByRole('link');
23
16
 
24
17
  expect(errorSummaryElement).toHaveClass('ds_error-summary');
25
18
  expect(errorSummaryElement).toHaveAttribute('role', 'alert');
@@ -27,24 +20,19 @@ test('error summary renders correctly', () => {
27
20
  expect(errorSummaryElement.tagName).toEqual('DIV');
28
21
 
29
22
  expect(errorSummaryTitle).toHaveClass('ds_error-summary__title');
30
- expect(errorSummaryTitle).toHaveAttribute('id', TITLE_ID);
23
+ expect(errorSummaryTitle).toHaveAttribute('id');
31
24
  expect(errorSummaryTitle.tagName).toEqual('H2');
32
25
  expect(errorSummaryTitle.textContent).toEqual('There is a problem');
33
26
 
34
27
  expect(errorSummaryList).toHaveClass('ds_error-summary__list');
35
28
  expect(errorSummaryList.tagName).toEqual('UL');
36
-
37
- expect(errorSummaryItems.length).toEqual(ERRORS.length);
38
-
39
- expect(errorSummaryLink1).toHaveAttribute('href', `#${ERRORS[0].fragmentId}`);
40
- expect(errorSummaryLink1.textContent).toEqual(ERRORS[0].title);
41
29
  });
42
30
 
43
31
  test('error summary with custom title', () => {
44
32
  const TITLE_TEXT = 'Foo';
45
33
 
46
34
  render(
47
- <ErrorSummary data-testid="errorsummary" errors={ERRORS} title={TITLE_TEXT} />
35
+ <ErrorSummary data-testid="errorsummary" title={TITLE_TEXT}/>
48
36
  );
49
37
 
50
38
  const errorSummaryElement = screen.getByTestId('errorsummary');
@@ -53,42 +41,60 @@ test('error summary with custom title', () => {
53
41
  expect(errorSummaryTitle.textContent).toEqual(TITLE_TEXT);
54
42
  });
55
43
 
56
- test('error summary with no errors (empty array) should not display', () => {
44
+ test('error summary item with link', () => {
57
45
  render(
58
- <ErrorSummary data-testid="errorsummary" errors={[]} />
46
+ <ErrorSummary.Item fragmentId={ERROR_FRAGMENT_ID}>{ERROR_TEXT}</ErrorSummary.Item>
59
47
  );
60
48
 
61
- const errorSummaryElement = screen.queryByTestId('errorsummary');
49
+ const errorSummaryItem = screen.getByRole('listitem');
50
+ const errorSummaryLink = within(errorSummaryItem).queryByRole('link');
51
+
52
+ expect(errorSummaryItem.tagName).toEqual('LI');
62
53
 
63
- expect(errorSummaryElement).not.toBeInTheDocument();
54
+ expect(errorSummaryLink).toBeInTheDocument();
55
+ expect(errorSummaryLink).toHaveAttribute('href', '#' + ERROR_FRAGMENT_ID);
56
+ expect(errorSummaryLink?.tagName).toEqual('A');
57
+ expect(errorSummaryLink?.textContent).toEqual(ERROR_TEXT);
64
58
  });
65
59
 
66
- test('error summary with no errors (no errors prop) should not display', () => {
60
+ test('error summary item with no link', () => {
67
61
  render(
68
- <ErrorSummary data-testid="errorsummary" />
62
+ <ErrorSummary.Item>{ERROR_TEXT}</ErrorSummary.Item>
69
63
  );
70
64
 
71
- const errorSummaryElement = screen.queryByTestId('errorsummary');
65
+ const errorSummaryItem = screen.getByRole('listitem');
66
+ const errorSummaryLink = within(errorSummaryItem).queryByRole('link');
72
67
 
73
- expect(errorSummaryElement).not.toBeInTheDocument();
68
+ expect(errorSummaryItem.tagName).toEqual('LI');
69
+
70
+ expect(errorSummaryLink).not.toBeInTheDocument();
71
+ expect(errorSummaryItem?.textContent).toEqual(ERROR_TEXT);
74
72
  });
75
73
 
76
- test('error sumary item with no link', () => {
74
+ test('error summary item with custom element', () => {
77
75
  render(
78
- <ErrorSummary data-testid="errorsummary" errors={[{ title: 'Did this resolve your issue?' }]} />
76
+ <ErrorSummary.Item fragmentId={ERROR_FRAGMENT_ID} linkComponent={
77
+ ({ className, ...props }) => (
78
+ <strong role="link" {...props}/>
79
+ )}>
80
+ {ERROR_TEXT}
81
+ </ErrorSummary.Item>
79
82
  );
80
83
 
81
- const errorSummaryElement = screen.getByTestId('errorsummary');
82
- const errorSummaryItems = within(errorSummaryElement).getAllByRole('listitem');
83
- const errorSummaryLink1 = within(errorSummaryItems[0]).queryByRole('link');
84
+ const errorSummaryItem = screen.getByRole('listitem');
85
+ const errorSummaryLink = within(errorSummaryItem).queryByRole('link');
86
+
87
+ expect(errorSummaryItem.tagName).toEqual('LI');
84
88
 
85
- expect(errorSummaryItems[0].textContent).toEqual('Did this resolve your issue?')
86
- expect(errorSummaryLink1).not.toBeInTheDocument();
89
+ expect(errorSummaryLink).toBeInTheDocument();
90
+ expect(errorSummaryLink).toHaveAttribute('href', '#' + ERROR_FRAGMENT_ID);
91
+ expect(errorSummaryLink?.tagName).toEqual('STRONG');
92
+ expect(errorSummaryLink?.textContent).toEqual(ERROR_TEXT);
87
93
  });
88
94
 
89
95
  test('passing additional props', () => {
90
96
  render(
91
- <ErrorSummary data-testid="errorsummary" errors={ERRORS} data-test="foo" />
97
+ <ErrorSummary data-testid="errorsummary" data-test="foo"/>
92
98
  )
93
99
 
94
100
  const errorSummaryElement = screen.getByTestId('errorsummary');
@@ -97,7 +103,7 @@ test('passing additional props', () => {
97
103
 
98
104
  test('passing additional CSS classes', () => {
99
105
  render(
100
- <ErrorSummary data-testid="errorsummary" errors={ERRORS} className="foo" />
106
+ <ErrorSummary data-testid="errorsummary" className="foo"/>
101
107
  )
102
108
 
103
109
  const errorSummaryElement = screen.getByTestId('errorsummary');
@@ -1,49 +1,57 @@
1
- import ConditionalWrapper from '../../common/ConditionalWrapper';
1
+ import { useId } from 'react';
2
2
 
3
- const Error: React.FC<SGDS.Component.ErrorSummary.Error> = ({
3
+ const ErrorSummaryItem = ({
4
+ children,
4
5
  fragmentId,
5
- title
6
- }) => {
6
+ linkComponent
7
+ }: SGDS.Component.ErrorSummary.Item) => {
8
+ const HREF = '#' + fragmentId;
9
+
10
+ function processChildren(children: React.ReactNode) {
11
+ if (linkComponent) {
12
+ return linkComponent({ className: '', href: HREF, children });
13
+ } else if (fragmentId) {
14
+ return <a href={HREF}>{children}</a>;
15
+ } else {
16
+ return children;
17
+ }
18
+ }
19
+
7
20
  return (
8
21
  <li>
9
- <ConditionalWrapper
10
- condition={!!fragmentId}
11
- wrapper={() => <a href={`#${fragmentId}`}>{title}</a>}
12
- >{title}</ConditionalWrapper>
22
+ {processChildren(children)}
13
23
  </li>
14
24
  );
15
- };
25
+ }
16
26
 
17
- const ErrorSummary: React.FC<SGDS.Component.ErrorSummary> = ({
27
+ const ErrorSummary = ({
28
+ children,
18
29
  className,
19
- errors,
20
30
  title = 'There is a problem',
21
31
  ...props
22
- }) => {
32
+ }: SGDS.Component.ErrorSummary) => {
33
+ const summaryTitleId = useId();
34
+
23
35
  return (
24
- <>
25
- {errors && errors.length && (
26
- <div className={[
27
- 'ds_error-summary',
28
- className
29
- ].join(' ')}
30
- aria-labelledby="error-summary-title"
31
- role="alert"
32
- {...props}
33
- >
34
- <h2 className="ds_error-summary__title" id="error-summary-title">{title}</h2>
35
-
36
- <ul className="ds_error-summary__list">
37
- {errors && errors.map((error, index: number) => (
38
- <Error fragmentId={error.fragmentId} title={error.title} key={'error' + index} />
39
- ))}
40
- </ul>
41
- </div>
42
- )}
43
- </>
36
+ <div className={[
37
+ 'ds_error-summary',
38
+ className
39
+ ].join(' ')}
40
+ aria-labelledby={summaryTitleId}
41
+ role="alert"
42
+ {...props}
43
+ >
44
+ <h2 className="ds_error-summary__title" id={summaryTitleId}>{title}</h2>
45
+
46
+ <ul className="ds_error-summary__list">
47
+ {children}
48
+ </ul>
49
+ </div>
44
50
  );
45
51
  };
46
52
 
47
53
  ErrorSummary.displayName = 'ErrorSummary';
54
+ ErrorSummaryItem.displayName = 'ErrorSummary.Item';
55
+ ErrorSummary.Item = ErrorSummaryItem;
48
56
 
49
57
  export default ErrorSummary;
@@ -1,7 +1,7 @@
1
1
  import { useId } from 'react';
2
2
  import FileIcon from '../../common/FileIcon';
3
3
 
4
- const FileDownload: React.FC<SGDS.Component.FileDownload> = ({
4
+ const FileDownload = ({
5
5
  className,
6
6
  cover,
7
7
  highlighted,
@@ -11,7 +11,7 @@ const FileDownload: React.FC<SGDS.Component.FileDownload> = ({
11
11
  fileUrl,
12
12
  title,
13
13
  ...props
14
- }) => {
14
+ }: SGDS.Component.FileDownload) => {
15
15
  const hasMetadata = !!fileType || !!fileSize;
16
16
  const metaContainerId = `file-download-${useId()}`;
17
17
 
@@ -2,11 +2,11 @@ import React, { useEffect, useRef } from 'react';
2
2
  // @ts-ignore
3
3
  import DSHideThisPage from '@scottish-government/design-system/src/components/hide-this-page/hide-this-page';
4
4
 
5
- const HideThisPage: React.FC<SGDS.Component.HideThisPage> = ({
5
+ const HideThisPage = ({
6
6
  className,
7
7
  escapeUrl = 'https://www.bbc.co.uk/weather',
8
8
  ...props
9
- }) => {
9
+ }: SGDS.Component.HideThisPage) => {
10
10
  const ref = useRef(null);
11
11
 
12
12
  useEffect(() => {
@@ -1,8 +1,8 @@
1
- const InsetText: React.FC<SGDS.Component.InsetText> = ({
1
+ const InsetText = ({
2
2
  children,
3
3
  className,
4
4
  ...props
5
- }) => {
5
+ }: SGDS.Component.InsetText) => {
6
6
  return (
7
7
  <div
8
8
  className={[
@@ -3,17 +3,16 @@ import AbstractNotificationBanner from '../../common/AbstractNotificationBanner'
3
3
  // @ts-ignore
4
4
  import DSNotificationBanner from '@scottish-government/design-system/src/components/notification-banner/notification-banner';
5
5
 
6
- const NotificationBanner: React.FC<SGDS.Common.AbstractNotificationBanner>
7
- & { Buttons?: React.FC<SGDS.Common.AbstractNotificationBanner.Buttons> } = ({
6
+ const NotificationBanner = ({
8
7
  children,
9
8
  className,
10
9
  close,
10
+ hasColourIcon,
11
+ hasInverseIcon,
11
12
  icon,
12
- iconColour,
13
- iconInverse,
14
13
  title,
15
14
  ...props
16
- }) => {
15
+ }: SGDS.Common.AbstractNotificationBanner) => {
17
16
  const ref = useRef(null);
18
17
 
19
18
  useEffect(() => {
@@ -30,8 +29,8 @@ const NotificationBanner: React.FC<SGDS.Common.AbstractNotificationBanner>
30
29
  ].join(' ')}
31
30
  close={close}
32
31
  icon={icon ? "PriorityHigh" : undefined}
33
- iconColour={iconColour}
34
- iconInverse={iconInverse}
32
+ hasColourIcon={hasColourIcon}
33
+ hasInverseIcon={hasInverseIcon}
35
34
  ref={ref}
36
35
  title="Information"
37
36
  {...props}
@@ -1,13 +1,13 @@
1
1
  import WrapperTag from '../../common/WrapperTag';
2
2
 
3
- const NotificationPanel: React.FC<SGDS.Component.NotificationPanel> = function ({
3
+ const NotificationPanel = function ({
4
4
  ariaLive,
5
5
  children,
6
6
  className,
7
7
  headingLevel = 'h1',
8
8
  title,
9
9
  ...props
10
- }) {
10
+ }: SGDS.Component.NotificationPanel) {
11
11
  return (
12
12
  <div
13
13
  aria-live={ariaLive}
@@ -1,10 +1,10 @@
1
- const PageHeader: React.FC<SGDS.Component.PageHeader> = ({
1
+ const PageHeader = ({
2
2
  children,
3
3
  className,
4
4
  label,
5
5
  title,
6
6
  ...props
7
- }) => {
7
+ }: SGDS.Component.PageHeader) => {
8
8
  return (
9
9
  <header
10
10
  className={[
@@ -1,9 +1,9 @@
1
- const MetadataItem: React.FC<SGDS.Component.Metadata.Item> = ({
1
+ const MetadataItem= ({
2
2
  children,
3
3
  className,
4
4
  name,
5
5
  ...props
6
- }) => {
6
+ }: SGDS.Component.Metadata.Item) => {
7
7
  return (
8
8
  <div className={[
9
9
  'ds_metadata__item',
@@ -19,13 +19,12 @@ const MetadataItem: React.FC<SGDS.Component.Metadata.Item> = ({
19
19
  );
20
20
  };
21
21
 
22
- const Metadata: React.FC<SGDS.Component.Metadata>
23
- & { Item: React.FC<SGDS.Component.Metadata.Item> } = ({
22
+ const Metadata = ({
24
23
  children,
25
24
  className,
26
25
  inline,
27
26
  ...props
28
- }) => {
27
+ }: SGDS.Component.Metadata) => {
29
28
  return (
30
29
  <dl
31
30
  className={[
@@ -4,7 +4,8 @@ import Pagination, { Page, Ellipsis } from './Pagination';
4
4
 
5
5
  const PAGE_ARIA_LABEL = 'Page 1';
6
6
  const PAGE_HREF = '#foo';
7
- const PAGE_TEXT = '1';
7
+ const PAGE_TEXT = 1;
8
+ const PAGE_LABEL = <span className="ds_pagination__link-label">{PAGE_TEXT}</span>;
8
9
  const CURRENT_PAGE = 10;
9
10
  const TOTAL_PAGES = 21;
10
11
 
@@ -13,8 +14,7 @@ test('pagination page renders correctly', () => {
13
14
  <Page
14
15
  ariaLabel={PAGE_ARIA_LABEL}
15
16
  href={PAGE_HREF}
16
- text={PAGE_TEXT}
17
- />
17
+ >{PAGE_LABEL}</Page>
18
18
  );
19
19
 
20
20
  const item = screen.getByRole('listitem');
@@ -25,6 +25,27 @@ test('pagination page renders correctly', () => {
25
25
  expect(link).toHaveClass('ds_pagination__link');
26
26
  expect(link).toHaveAttribute('aria-label', PAGE_ARIA_LABEL);
27
27
  expect(link).toHaveAttribute('href', PAGE_HREF);
28
+ expect(link.tagName).toEqual('A');
29
+ expect(span).toHaveClass('ds_pagination__link-label');
30
+ });
31
+
32
+ test('pagination page renders with custom link component', () => {
33
+ render(
34
+ <Page
35
+ ariaLabel={PAGE_ARIA_LABEL}
36
+ href={PAGE_HREF}
37
+ linkComponent={
38
+ ({ className, ...props }) => (
39
+ <span role="link" className={className} {...props}/>
40
+ )}
41
+ >{PAGE_LABEL}</Page>
42
+ );
43
+
44
+ const item = screen.getByRole('listitem');
45
+ const link = within(item).getByRole('link');
46
+ const span = within(link).getByText(PAGE_TEXT);
47
+
48
+ expect(link.tagName).toEqual('SPAN');
28
49
  expect(span).toHaveClass('ds_pagination__link-label');
29
50
  });
30
51
 
@@ -33,9 +54,8 @@ test('current pagination page', () => {
33
54
  <Page
34
55
  ariaLabel={PAGE_ARIA_LABEL}
35
56
  href={PAGE_HREF}
36
- text={PAGE_TEXT}
37
57
  current
38
- />
58
+ >{PAGE_LABEL}</Page>
39
59
  );
40
60
 
41
61
  const item = screen.getByRole('listitem');
@@ -52,9 +72,8 @@ test('pagination page with click event', () => {
52
72
  <Page
53
73
  ariaLabel={PAGE_ARIA_LABEL}
54
74
  href={PAGE_HREF}
55
- text={PAGE_TEXT}
56
75
  onClick={ONCLICK_FUNCTION}
57
- />
76
+ >{PAGE_LABEL}</Page>
58
77
  );
59
78
 
60
79
  const item = screen.getByRole('listitem');
@@ -1,31 +1,51 @@
1
1
  import Icon from "../../common/Icon";
2
2
 
3
- export const Page: React.FC<SGDS.Component.Pagination.Page> = ({
3
+ export const Page = ({
4
4
  ariaLabel,
5
+ children,
6
+ className,
5
7
  current = false,
6
8
  href,
7
- onClick,
8
- text
9
- }) => {
9
+ linkComponent,
10
+ onClick
11
+ }: SGDS.Component.Pagination.Page) => {
10
12
  function handleClick(event: React.MouseEvent) {
11
13
  if (typeof onClick === 'function') {
12
14
  onClick(event);
13
15
  }
14
16
  }
15
17
 
18
+ function processChildren(children: React.ReactNode) {
19
+ const classNames = [
20
+ 'ds_pagination__link',
21
+ className,
22
+ current ? 'ds_current' : undefined
23
+ ].join(' ');
24
+
25
+ const linkProps: SGDS.LinkComponentProps = {
26
+ 'aria-label': ariaLabel,
27
+ href: href,
28
+ onClick: handleClick
29
+ };
30
+
31
+ if (current) {
32
+ linkProps['aria-current'] = 'page';
33
+ }
34
+
35
+ if (linkComponent) {
36
+ return linkComponent({ className: classNames, children: children, ...linkProps });
37
+ } else if (href) {
38
+ return (
39
+ <a href={href} className={classNames} {...linkProps}>
40
+ {children}
41
+ </a>
42
+ );
43
+ }
44
+ }
45
+
16
46
  return (
17
47
  <li className="ds_pagination__item">
18
- <a aria-label={ariaLabel}
19
- className={[
20
- 'ds_pagination__link',
21
- current ? 'ds_current' : undefined
22
- ].join(' ')}
23
- href={href}
24
- aria-current={current ? "page" : undefined}
25
- onClick={handleClick}
26
- >
27
- <span className="ds_pagination__link-label">{text}</span>
28
- </a>
48
+ {processChildren(children)}
29
49
  </li>
30
50
  );
31
51
  };
@@ -38,7 +58,7 @@ export const Ellipsis = () => {
38
58
  );
39
59
  };
40
60
 
41
- const Pagination: React.FC<SGDS.Component.Pagination> = ({
61
+ const Pagination = ({
42
62
  ariaLabel = 'Pages',
43
63
  className,
44
64
  onClick,
@@ -46,8 +66,9 @@ const Pagination: React.FC<SGDS.Component.Pagination> = ({
46
66
  page = 1,
47
67
  pattern = '/search?page=$1',
48
68
  totalPages,
69
+ linkComponent,
49
70
  ...props
50
- }) => {
71
+ }: SGDS.Component.Pagination) => {
51
72
  padding = Number(padding);
52
73
  page = Number(page);
53
74
 
@@ -93,12 +114,16 @@ const Pagination: React.FC<SGDS.Component.Pagination> = ({
93
114
  >
94
115
  <ul className="ds_pagination__list">
95
116
  {page > 1 && (
96
- <li className="ds_pagination__item">
97
- <a aria-label="Previous page" className="ds_pagination__link ds_pagination__link--text ds_pagination__link--icon" href={pattern.replace('$1', String(page - 1))} data-search="pagination-previous" onClick={onClick}>
98
- <Icon icon="ChevronLeft" />
99
- <span className="ds_pagination__link-label">Previous</span>
100
- </a>
101
- </li>
117
+ <Page
118
+ ariaLabel="Previous page"
119
+ className="ds_pagination__link--text ds_pagination__link--icon"
120
+ data-search="pagination-previous"
121
+ href={pattern.replace('$1', String(page - 1))}
122
+ onClick={onClick}
123
+ >
124
+ <Icon icon="ChevronLeft" />
125
+ <span className="ds_pagination__link-label">Previous</span>
126
+ </Page>
102
127
  )}
103
128
 
104
129
  {includeFirst && (
@@ -107,8 +132,10 @@ const Pagination: React.FC<SGDS.Component.Pagination> = ({
107
132
  ariaLabel="Page 1"
108
133
  href={pattern.replace('$1', String(1))}
109
134
  onClick={onClick}
110
- text="1"
111
- />
135
+ linkComponent={linkComponent}
136
+ >
137
+ <span className="ds_pagination__link-label">1</span>
138
+ </Page>
112
139
  <Ellipsis/>
113
140
  </>
114
141
  )}
@@ -116,13 +143,15 @@ const Pagination: React.FC<SGDS.Component.Pagination> = ({
116
143
  {pages && pages.map((item, index: number) => (
117
144
  <Page
118
145
  ariaLabel={`Page ${item}`}
119
- current={item === page}
120
146
  href={pattern.replace('$1', String(item))}
147
+ current={item === page}
121
148
  key={`pagination${index}`}
149
+ linkComponent={linkComponent}
122
150
  onClick={onClick}
123
151
  pattern={pattern}
124
- text={item.toString()}
125
- />
152
+ >
153
+ <span className="ds_pagination__link-label">{item.toString()}</span>
154
+ </Page>
126
155
  ))}
127
156
 
128
157
  {includeLast && (
@@ -131,20 +160,25 @@ const Pagination: React.FC<SGDS.Component.Pagination> = ({
131
160
  <Page
132
161
  ariaLabel={`Page ${totalPages}`}
133
162
  href={pattern.replace('$1', String(totalPages))}
163
+ linkComponent={linkComponent}
134
164
  onClick={onClick}
135
165
  pattern={pattern}
136
- text={totalPages.toString()}
137
- />
166
+ >
167
+ <span className="ds_pagination__link-label">{totalPages.toString()}</span>
168
+ </Page>
138
169
  </>
139
170
  )}
140
171
 
141
172
  {page < totalPages && (
142
- <li className="ds_pagination__item">
143
- <a aria-label="Next page" className="ds_pagination__link ds_pagination__link--text ds_pagination__link--icon" href={pattern.replace('$1', String(page + 1))} data-search="pagination-next" onClick={onClick}>
144
- <span className="ds_pagination__link-label">Next</span>
145
- <Icon icon="ChevronRight" />
146
- </a>
147
- </li>
173
+ <Page
174
+ ariaLabel="Next page"
175
+ href={pattern.replace('$1', String(page + 1))}
176
+ className="ds_pagination__link ds_pagination__link--text ds_pagination__link--icon"
177
+ onClick={onClick}
178
+ >
179
+ <span className="ds_pagination__link-label">Next</span>
180
+ <Icon icon="ChevronRight" />
181
+ </Page>
148
182
  )}
149
183
 
150
184
  </ul>
@@ -1,12 +1,11 @@
1
1
  import Tag from "../Tag/Tag";
2
2
 
3
- const PhaseBanner: React.FC<SGDS.Component.PhaseBanner> = ({
3
+ const PhaseBanner = ({
4
4
  children,
5
5
  className,
6
- content,
7
6
  phaseName,
8
7
  ...props
9
- }) => {
8
+ }: SGDS.Component.PhaseBanner) => {
10
9
  return (
11
10
  <div
12
11
  className={[
@@ -17,9 +16,9 @@ const PhaseBanner: React.FC<SGDS.Component.PhaseBanner> = ({
17
16
  >
18
17
  <div className="ds_wrapper">
19
18
  <p className="ds_phase-banner__content">
20
- {phaseName && <Tag title={phaseName} className="ds_phase-banner__tag" />}
19
+ {phaseName && <Tag className="ds_phase-banner__tag">{phaseName}</Tag>}
21
20
  <span className="ds_phase-banner__text">
22
- {content ? content : children || "This is a new service"}
21
+ {children || "This is a new service"}
23
22
  </span>
24
23
  </p>
25
24
  </div>
@@ -46,7 +46,7 @@ test('question with error', () => {
46
46
  const ERROR_MESSAGE_TEXT = 'My error message';
47
47
 
48
48
  render(
49
- <Question error errorMessage={ERROR_MESSAGE_TEXT}>
49
+ <Question hasError errorMessage={ERROR_MESSAGE_TEXT}>
50
50
  </Question>
51
51
  );
52
52