@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.
Files changed (211) 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/Accordion.d.ts +0 -1
  6. package/@types/components/Breadcrumbs.d.ts +2 -5
  7. package/@types/components/Checkbox.d.ts +0 -2
  8. package/@types/components/ConfirmationMessage.d.ts +1 -1
  9. package/@types/components/ContentsNav.d.ts +4 -6
  10. package/@types/components/DatePicker.d.ts +1 -1
  11. package/@types/components/ErrorSummary.d.ts +3 -4
  12. package/@types/components/NotificationPanel.d.ts +1 -1
  13. package/@types/components/Pagination.d.ts +5 -4
  14. package/@types/components/PhaseBanner.d.ts +0 -1
  15. package/@types/components/Question.d.ts +1 -1
  16. package/@types/components/RadioButton.d.ts +0 -1
  17. package/@types/components/Select.d.ts +0 -7
  18. package/@types/components/SequentialNavigation.d.ts +4 -4
  19. package/@types/components/SideNavigation.d.ts +4 -5
  20. package/@types/components/SiteFooter.d.ts +25 -0
  21. package/@types/components/SiteHeader.d.ts +10 -3
  22. package/@types/components/SiteNavigation.d.ts +2 -3
  23. package/@types/components/SkipLinks.d.ts +3 -4
  24. package/@types/components/SummaryCard.d.ts +0 -2
  25. package/@types/components/SummaryList.d.ts +0 -13
  26. package/@types/components/Tabs.d.ts +0 -1
  27. package/@types/components/Tag.d.ts +1 -3
  28. package/@types/components/TaskList.d.ts +1 -0
  29. package/@types/sgds.d.ts +13 -2
  30. package/CHANGELOG.md +63 -1
  31. package/dist/common/AbstractNotificationBanner.jsx +8 -6
  32. package/dist/common/ActionLink.jsx +19 -0
  33. package/dist/common/FileIcon.jsx +2 -7
  34. package/dist/common/Icon.jsx +3 -9
  35. package/dist/components/Accordion/Accordion.jsx +12 -7
  36. package/dist/components/Breadcrumbs/Breadcrumbs.jsx +20 -15
  37. package/dist/components/Checkbox/Checkbox.jsx +4 -29
  38. package/dist/components/{aspect-box/aspect-box.jsx → Checkbox/CheckboxGroup.jsx} +14 -30
  39. package/dist/components/ContentsNav/ContentsNav.jsx +27 -16
  40. package/dist/components/CookieBanner/CookieBanner.jsx +1 -0
  41. package/dist/components/DatePicker/DatePicker.jsx +5 -5
  42. package/dist/components/ErrorSummary/ErrorSummary.jsx +28 -18
  43. package/dist/components/NotificationBanner/NotificationBanner.jsx +2 -2
  44. package/dist/components/Pagination/Pagination.jsx +42 -22
  45. package/dist/components/PhaseBanner/PhaseBanner.jsx +3 -3
  46. package/dist/components/Question/Question.jsx +3 -3
  47. package/dist/components/RadioButton/RadioButton.jsx +7 -17
  48. package/dist/components/RadioButton/RadioGroup.jsx +21 -0
  49. package/dist/components/Select/Select.jsx +4 -7
  50. package/dist/components/SequentialNavigation/SequentialNavigation.jsx +31 -18
  51. package/dist/components/SideNavigation/SideNavigation.jsx +17 -16
  52. package/dist/components/SiteFooter/SiteFooter.jsx +104 -0
  53. package/dist/components/SiteHeader/SiteHeader.jsx +113 -32
  54. package/dist/components/SiteNavigation/SiteNavigation.jsx +20 -7
  55. package/dist/components/SkipLinks/SkipLinks.jsx +10 -10
  56. package/dist/components/SummaryCard/SummaryCard.jsx +25 -14
  57. package/dist/components/SummaryList/SummaryList.jsx +65 -47
  58. package/dist/components/Tabs/Tabs.jsx +6 -6
  59. package/dist/components/Tag/Tag.jsx +2 -2
  60. package/dist/components/TaskList/TaskList.jsx +14 -3
  61. package/dist/components/TextInput/TextInput.jsx +3 -3
  62. package/dist/components/Textarea/Textarea.jsx +3 -3
  63. package/dist/hooks/useTracking.js +21 -0
  64. package/dist/tsconfig.tsbuildinfo +1 -1
  65. package/dist/utils/context.js +5 -0
  66. package/package.json +2 -2
  67. package/src/common/AbstractNotificationBanner.test.tsx +1 -1
  68. package/src/common/AbstractNotificationBanner.tsx +14 -13
  69. package/src/common/ActionLink.test.tsx +80 -0
  70. package/src/common/ActionLink.tsx +27 -0
  71. package/src/common/ConditionalWrapper.tsx +1 -1
  72. package/src/common/FileIcon.tsx +7 -11
  73. package/src/common/HintText.tsx +2 -2
  74. package/src/common/Icon.tsx +13 -17
  75. package/src/common/ScreenReaderText.tsx +2 -2
  76. package/src/common/WrapperTag.tsx +2 -2
  77. package/src/components/Accordion/Accordion.test.tsx +17 -4
  78. package/src/components/Accordion/Accordion.tsx +19 -14
  79. package/src/components/AspectBox/AspectBox.tsx +2 -2
  80. package/src/components/BackToTop/BackToTop.tsx +2 -2
  81. package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +79 -48
  82. package/src/components/Breadcrumbs/Breadcrumbs.tsx +31 -31
  83. package/src/components/Button/Button.tsx +2 -2
  84. package/src/components/Checkbox/Checkbox.test.tsx +1 -96
  85. package/src/components/Checkbox/Checkbox.tsx +8 -55
  86. package/src/components/Checkbox/CheckboxGroup.test.tsx +37 -0
  87. package/src/components/Checkbox/CheckboxGroup.tsx +41 -0
  88. package/src/components/ConfirmationMessage/ConfirmationMessage.tsx +2 -2
  89. package/src/components/ContentsNav/ContentsNav.test.tsx +40 -51
  90. package/src/components/ContentsNav/ContentsNav.tsx +32 -25
  91. package/src/components/CookieBanner/CookieBanner.tsx +3 -3
  92. package/src/components/DatePicker/DatePicker.test.tsx +1 -1
  93. package/src/components/DatePicker/DatePicker.tsx +7 -7
  94. package/src/components/Details/Details.tsx +2 -2
  95. package/src/components/ErrorMessage/ErrorMessage.tsx +2 -2
  96. package/src/components/ErrorSummary/ErrorSummary.test.tsx +40 -34
  97. package/src/components/ErrorSummary/ErrorSummary.tsx +40 -32
  98. package/src/components/FileDownload/FileDownload.tsx +2 -2
  99. package/src/components/HideThisPage/HideThisPage.tsx +2 -2
  100. package/src/components/InsetText/InsetText.tsx +2 -2
  101. package/src/components/NotificationBanner/NotificationBanner.tsx +6 -7
  102. package/src/components/NotificationPanel/NotificationPanel.tsx +2 -2
  103. package/src/components/PageHeader/PageHeader.tsx +2 -2
  104. package/src/components/PageMetadata/PageMetadata.tsx +4 -5
  105. package/src/components/Pagination/Pagination.test.tsx +26 -7
  106. package/src/components/Pagination/Pagination.tsx +70 -36
  107. package/src/components/PhaseBanner/PhaseBanner.tsx +4 -5
  108. package/src/components/Question/Question.test.tsx +1 -1
  109. package/src/components/Question/Question.tsx +5 -5
  110. package/src/components/RadioButton/RadioButton.test.tsx +7 -126
  111. package/src/components/RadioButton/RadioButton.tsx +10 -41
  112. package/src/components/RadioButton/RadioGroup.test.tsx +65 -0
  113. package/src/components/RadioButton/RadioGroup.tsx +31 -0
  114. package/src/components/Select/Select.test.tsx +39 -37
  115. package/src/components/Select/Select.tsx +7 -22
  116. package/src/components/SequentialNavigation/SequentialNavigation.test.tsx +32 -21
  117. package/src/components/SequentialNavigation/SequentialNavigation.tsx +52 -30
  118. package/src/components/SideNavigation/SideNavigation.test.tsx +39 -85
  119. package/src/components/SideNavigation/SideNavigation.tsx +27 -29
  120. package/src/components/SiteFooter/SiteFooter.test.tsx +153 -0
  121. package/src/components/SiteFooter/SiteFooter.tsx +107 -0
  122. package/src/components/SiteHeader/SiteHeader.test.tsx +87 -79
  123. package/src/components/SiteHeader/SiteHeader.tsx +103 -40
  124. package/src/components/SiteNavigation/SiteNavigation.test.tsx +42 -23
  125. package/src/components/SiteNavigation/SiteNavigation.tsx +28 -16
  126. package/src/components/SiteSearch/SiteSearch.tsx +2 -2
  127. package/src/components/SkipLinks/SkipLinks.test.tsx +22 -10
  128. package/src/components/SkipLinks/SkipLinks.tsx +16 -15
  129. package/src/components/SummaryCard/SummaryCard.test.tsx +31 -35
  130. package/src/components/SummaryCard/SummaryCard.tsx +39 -28
  131. package/src/components/SummaryList/SummaryList.test.tsx +49 -148
  132. package/src/components/SummaryList/SummaryList.tsx +54 -92
  133. package/src/components/Table/Table.tsx +2 -2
  134. package/src/components/Tabs/Tabs.tsx +14 -15
  135. package/src/components/Tag/Tag.test.tsx +4 -4
  136. package/src/components/Tag/Tag.tsx +4 -4
  137. package/src/components/TaskList/TaskList.test.tsx +26 -0
  138. package/src/components/TaskList/TaskList.tsx +21 -11
  139. package/src/components/TextInput/TextInput.test.tsx +1 -1
  140. package/src/components/TextInput/TextInput.tsx +5 -5
  141. package/src/components/Textarea/Textarea.test.tsx +1 -1
  142. package/src/components/Textarea/Textarea.tsx +5 -5
  143. package/src/components/WarningText/WarningText.tsx +2 -2
  144. package/src/hooks/useTracking.test.tsx +64 -0
  145. package/src/hooks/useTracking.ts +19 -0
  146. package/src/utils/context.ts +3 -0
  147. package/tsconfig.json +1 -1
  148. package/dist/common/abstract-notification-banner.jsx +0 -63
  149. package/dist/common/conditional-wrapper.jsx +0 -8
  150. package/dist/common/file-icon.jsx +0 -51
  151. package/dist/common/hint-text.jsx +0 -9
  152. package/dist/common/icon.jsx +0 -57
  153. package/dist/common/screen-reader-text.jsx +0 -9
  154. package/dist/common/wrapper-tag.jsx +0 -11
  155. package/dist/components/accordion/accordion.jsx +0 -102
  156. package/dist/components/back-to-top/back-to-top.jsx +0 -27
  157. package/dist/components/breadcrumbs/breadcrumbs.jsx +0 -28
  158. package/dist/components/button/button.jsx +0 -30
  159. package/dist/components/checkbox/checkbox.jsx +0 -62
  160. package/dist/components/confirmation-message/confirmation-message.jsx +0 -24
  161. package/dist/components/contents-nav/contents-nav.jsx +0 -33
  162. package/dist/components/cookie-banner/cookie-banner.jsx +0 -21
  163. package/dist/components/date-picker/date-picker.jsx +0 -54
  164. package/dist/components/details/details.jsx +0 -17
  165. package/dist/components/error-message/error-message.jsx +0 -12
  166. package/dist/components/error-summary/error-summary.jsx +0 -27
  167. package/dist/components/file-download/file-download.jsx +0 -50
  168. package/dist/components/hide-this-page/hide-this-page.jsx +0 -71
  169. package/dist/components/inset-text/inset-text.jsx +0 -14
  170. package/dist/components/notification-banner/notification-banner.jsx +0 -26
  171. package/dist/components/notification-panel/notification-panel.jsx +0 -21
  172. package/dist/components/page-header/page-header.jsx +0 -15
  173. package/dist/components/page-metadata/page-metadata.jsx +0 -26
  174. package/dist/components/pagination/pagination.jsx +0 -97
  175. package/dist/components/phase-banner/phase-banner.jsx +0 -23
  176. package/dist/components/question/question.jsx +0 -22
  177. package/dist/components/radio-button/radio-button.jsx +0 -43
  178. package/dist/components/select/select.jsx +0 -52
  179. package/dist/components/sequential-navigation/sequential-navigation.jsx +0 -31
  180. package/dist/components/side-navigation/side-navigation.jsx +0 -52
  181. package/dist/components/site-header/site-header.jsx +0 -68
  182. package/dist/components/site-navigation/site-navigation.jsx +0 -22
  183. package/dist/components/site-search/site-search.jsx +0 -55
  184. package/dist/components/skip-links/skip-links.jsx +0 -21
  185. package/dist/components/summary-card/summary-card.jsx +0 -67
  186. package/dist/components/summary-list/summary-list.jsx +0 -75
  187. package/dist/components/table/table.jsx +0 -24
  188. package/dist/components/tabs/tabs.jsx +0 -99
  189. package/dist/components/tag/tag.jsx +0 -13
  190. package/dist/components/task-list/task-list.jsx +0 -95
  191. package/dist/components/text-input/text-input.jsx +0 -58
  192. package/dist/components/textarea/textarea.jsx +0 -54
  193. package/dist/components/warning-text/warning-text.jsx +0 -16
  194. package/dist/icons/ArrowUpward.jsx +0 -41
  195. package/dist/icons/CalendarToday.jsx +0 -41
  196. package/dist/icons/Cancel.jsx +0 -40
  197. package/dist/icons/CheckCircle.jsx +0 -41
  198. package/dist/icons/ChevronLeft.jsx +0 -41
  199. package/dist/icons/ChevronRight.jsx +0 -41
  200. package/dist/icons/Close.jsx +0 -41
  201. package/dist/icons/Description.jsx +0 -41
  202. package/dist/icons/DoubleChevronLeft.jsx +0 -40
  203. package/dist/icons/DoubleChevronRight.jsx +0 -40
  204. package/dist/icons/Error.jsx +0 -41
  205. package/dist/icons/ExpandLess.jsx +0 -41
  206. package/dist/icons/ExpandMore.jsx +0 -41
  207. package/dist/icons/List.jsx +0 -44
  208. package/dist/icons/Menu.jsx +0 -41
  209. package/dist/icons/PriorityHigh.jsx +0 -42
  210. package/dist/icons/Search.jsx +0 -41
  211. package/dist/icons/index.js +0 -40
@@ -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
 
@@ -2,29 +2,29 @@ import ErrorMessage from '../ErrorMessage/ErrorMessage';
2
2
  import HintText from '../../common/HintText';
3
3
  import WrapperTag from '../../common/WrapperTag';
4
4
 
5
- const Question: React.FC<SGDS.Component.Question> = function ({
5
+ const Question = function ({
6
6
  children,
7
7
  className,
8
- error,
9
8
  errorMessage,
9
+ hasError,
10
10
  hintText,
11
11
  legend,
12
12
  tagName = 'div',
13
13
  ...props
14
- }) {
14
+ }: SGDS.Component.Question) {
15
15
  return (
16
16
  <WrapperTag
17
17
  tagName={tagName}
18
18
  className={[
19
19
  'ds_question',
20
- error && 'ds_question--error',
20
+ hasError && 'ds_question--error',
21
21
  className
22
22
  ].join(' ')}
23
23
  {...props}
24
24
  >
25
25
  {legend && <legend>{legend}</legend>}
26
26
  {hintText && <HintText text={hintText} />}
27
- {error && errorMessage && <ErrorMessage text={errorMessage} />}
27
+ {hasError && errorMessage && <ErrorMessage text={errorMessage} />}
28
28
  {children}
29
29
  </WrapperTag>
30
30
  );
@@ -1,103 +1,10 @@
1
1
  import { test, expect, vi } from 'vitest';
2
2
  import { render, screen, fireEvent } from '@testing-library/react';
3
- import RadioGroup, { Radio } from './RadioButton';
4
-
5
- test('radio group renders correct children', () => {
6
- const ITEMS = [
7
- {
8
- id: 'universal-credit',
9
- label: 'Universal Credit',
10
- checked: true
11
- },
12
- {
13
- id: 'pensioncredit',
14
- label: 'Pension Credit'
15
- },
16
- {
17
- id: 'jsa',
18
- label: 'Income-based Job Seeker\'s Allowance',
19
- },
20
- {
21
- id: 'none',
22
- label: 'I do not receive any of these benefits',
23
- }
24
- ];
25
- const GROUP_NAME = "foo"
26
-
27
- render(
28
- <RadioGroup name={GROUP_NAME} items={ITEMS} />
29
- );
30
-
31
- const radios = screen.getAllByRole('radio');
32
- const groupContainer = radios[0].parentElement?.parentElement;
33
- expect(radios.length).toEqual(ITEMS.length);
34
- expect(groupContainer).toHaveClass('ds_radios', 'ds_field-group');
35
- });
36
-
37
- test('inline radio group', () => {
38
- const ITEMS = [
39
- {
40
- id: 'radio-yes',
41
- label: 'Yes'
42
- },
43
- {
44
- id: 'radio-no',
45
- label: 'No'
46
- }
47
- ];
48
- const GROUP_NAME = "yesno"
49
-
50
- render(
51
- <RadioGroup inline name={GROUP_NAME} items={ITEMS} />
52
- );
53
-
54
-
55
- const radio = screen.getAllByRole('radio')[0];
56
- const groupContainer = radio.parentElement?.parentElement;
57
- expect(groupContainer).toHaveClass('ds_field-group--inline');
58
- });
59
-
60
- test('radio group passes all expected item params', () => {
61
- const ONBLUR_FUNCTION = vi.fn();
62
- const ONCHANGE_FUNCTION = vi.fn();
63
- const GROUP_NAME = "foo"
64
-
65
- render(
66
- <RadioGroup name={GROUP_NAME} small items={[
67
- {
68
- checked: true,
69
- exclusive: true,
70
- hintText: 'hint text',
71
- id: 'myid',
72
- label: 'label text',
73
- onBlur: {ONBLUR_FUNCTION},
74
- onChange: {ONCHANGE_FUNCTION},
75
- small: true
76
- }
77
- ]}/>
78
- );
79
-
80
- const radio = screen.getByRole('radio');
81
- const radioContainer = radio.parentElement;
82
- const hintText = screen.getByText('hint text');
83
-
84
- expect(radio).toHaveAttribute('checked');
85
- expect(radio).toHaveAttribute('name', GROUP_NAME);
86
- expect(radio.id).toEqual('myid');
87
- expect(radioContainer).toHaveClass('ds_radio--small');
88
- expect(hintText).toBeInTheDocument();
89
- expect(radio).toHaveAttribute('aria-describedby', hintText.id);
90
-
91
- // fireEvent.blur(radio);
92
- // expect(ONBLUR_FUNCTION).toHaveBeenCalled();
93
-
94
- // fireEvent.click(radio);
95
- // expect(ONCHANGE_FUNCTION).toHaveBeenCalled();
96
- });
3
+ import RadioButton from './RadioButton';
97
4
 
98
5
  test('individual radio renders correctly', () => {
99
6
  render(
100
- <Radio name="benefitType" label="Pension Credit" id="pensioncredit" />
7
+ <RadioButton name="benefitType" label="Pension Credit" id="pensioncredit" />
101
8
  );
102
9
 
103
10
  const radio = screen.getByRole('radio');
@@ -117,7 +24,7 @@ test('individual radio renders correctly', () => {
117
24
 
118
25
  test('checked radio', () => {
119
26
  render(
120
- <Radio name="benefitType" checked label="Pension Credit" id="pensioncredit" />
27
+ <RadioButton name="benefitType" checked label="Pension Credit" id="pensioncredit" />
121
28
  );
122
29
 
123
30
  const radio = screen.getByRole('radio');
@@ -129,7 +36,7 @@ test('radio with blur fn', () => {
129
36
  const ONBLUR_FUNCTION = vi.fn();
130
37
 
131
38
  render(
132
- <Radio onBlur={ONBLUR_FUNCTION} name="benefitType" label="Pension Credit" id="pensioncredit" />
39
+ <RadioButton onBlur={ONBLUR_FUNCTION} name="benefitType" label="Pension Credit" id="pensioncredit" />
133
40
  );
134
41
 
135
42
  const radio = screen.getByRole('radio');
@@ -143,7 +50,7 @@ test('radio with change fn', () => {
143
50
  const ONCHANGE_FUNCTION = vi.fn();
144
51
 
145
52
  render(
146
- <Radio onChange={ONCHANGE_FUNCTION} name="benefitType" label="Pension Credit" id="pensioncredit" />
53
+ <RadioButton onChange={ONCHANGE_FUNCTION} name="benefitType" label="Pension Credit" id="pensioncredit" />
147
54
  );
148
55
 
149
56
  const radio = screen.getByRole('radio');
@@ -155,7 +62,7 @@ test('radio with change fn', () => {
155
62
 
156
63
  test('radio with hint text', () => {
157
64
  render(
158
- <Radio hintText="hint text" name="benefitType" label="Pension Credit" id="pensioncredit" />
65
+ <RadioButton hintText="hint text" name="benefitType" label="Pension Credit" id="pensioncredit" />
159
66
  );
160
67
 
161
68
  const hintText = screen.getByText('hint text');
@@ -167,7 +74,7 @@ test('radio with hint text', () => {
167
74
 
168
75
  test('small radio', () => {
169
76
  render(
170
- <Radio small name="benefitType" label="Pension Credit" id="pensioncredit" />
77
+ <RadioButton small name="benefitType" label="Pension Credit" id="pensioncredit" />
171
78
  );
172
79
 
173
80
  const radio = screen.getByRole('radio');
@@ -175,29 +82,3 @@ test('small radio', () => {
175
82
 
176
83
  expect(radioContainer).toHaveClass('ds_radio--small');
177
84
  });
178
-
179
- test('passing additional props', () => {
180
- render(
181
- <RadioGroup data-test="foo" items={[{
182
- id: 'universal-credit',
183
- label: 'Universal Credit'
184
- }]} />
185
- );
186
-
187
- const radios = screen.getAllByRole('radio');
188
- const groupContainer = radios[0]?.parentElement?.parentElement;
189
- expect(groupContainer?.dataset.test).toEqual('foo');
190
- });
191
-
192
- test('passing additional CSS classes', () => {
193
- render(
194
- <RadioGroup className="foo" items={[{
195
- id: 'universal-credit',
196
- label: 'Universal Credit'
197
- }]} />
198
- );
199
-
200
- const radios = screen.getAllByRole('radio');
201
- const groupContainer = radios[0]?.parentElement?.parentElement;
202
- expect(groupContainer).toHaveClass('foo', 'ds_radios');
203
- });
@@ -1,6 +1,9 @@
1
+ import { useContext } from 'react';
2
+
1
3
  import HintText from '../../common/HintText';
4
+ import { CheckboxRadioContext } from '../../utils/context';
2
5
 
3
- export const Radio: React.FC<SGDS.Component.RadioButton> = ({
6
+ const RadioButton = ({
4
7
  checked,
5
8
  hintText,
6
9
  id,
@@ -9,7 +12,7 @@ export const Radio: React.FC<SGDS.Component.RadioButton> = ({
9
12
  onBlur,
10
13
  onChange,
11
14
  small
12
- }) => {
15
+ }: SGDS.Component.RadioButton) => {
13
16
  const hintTextId = `hint-text-${id}`;
14
17
 
15
18
  function handleBlur(event: React.FocusEvent) {
@@ -24,6 +27,9 @@ export const Radio: React.FC<SGDS.Component.RadioButton> = ({
24
27
  }
25
28
  }
26
29
 
30
+ small = small || useContext(CheckboxRadioContext).small;
31
+ name = name || useContext(CheckboxRadioContext).name;
32
+
27
33
  return (
28
34
  <div
29
35
  className={[
@@ -48,43 +54,6 @@ export const Radio: React.FC<SGDS.Component.RadioButton> = ({
48
54
  );
49
55
  };
50
56
 
51
- const RadioGroup: React.FC<SGDS.Component.RadioButton.Group> = ({
52
- className,
53
- inline,
54
- items,
55
- name,
56
- small,
57
- ...props
58
- }) => {
59
- return (
60
- <div
61
- className={[
62
- 'ds_radios',
63
- 'ds_field-group',
64
- inline && 'ds_field-group--inline',
65
- className
66
- ].join(' ')}
67
- {...props}
68
- >
69
-
70
- {items && items.map((item, index: number) => (
71
- <Radio
72
- checked={item.checked}
73
- hintText={item.hintText}
74
- id={item.id}
75
- key={'radio' + index}
76
- label={item.label}
77
- name={name}
78
- onBlur={item.onBlur}
79
- onChange={item.onChange}
80
- small={small || item.small}
81
- />
82
- ))}
83
- </div>
84
- )
85
- };
86
-
87
- Radio.displayName = 'Radio';
88
- RadioGroup.displayName = 'RadioGroup';
57
+ RadioButton.displayName = 'RadioButton';
89
58
 
90
- export default RadioGroup;
59
+ export default RadioButton;
@@ -0,0 +1,65 @@
1
+ import { test, expect } from 'vitest';
2
+ import { render, screen } from '@testing-library/react';
3
+ import RadioButton from './RadioButton';
4
+ import RadioGroup from './RadioGroup';
5
+
6
+ test('radio group renders correctly', () => {
7
+ render(
8
+ <RadioGroup name="foo" data-testid="radiogroup">
9
+ <RadioButton id="banana" label="Banana" />
10
+ </RadioGroup>
11
+ );
12
+ const radioGroup = screen.getByTestId('radiogroup');
13
+ expect(radioGroup).toHaveClass('ds_radios', 'ds_field-group');
14
+ expect(radioGroup).not.toHaveClass('ds_field-group--inline');
15
+
16
+ const radio = screen.getByRole('radio');
17
+ const radioContainer = radio.parentElement;
18
+ expect(radioContainer).not.toHaveClass('ds_radio--small');
19
+ });
20
+
21
+ test('radio group passes all expected item params', () => {
22
+ const RADIO_NAME = 'radioname';
23
+
24
+ render(
25
+ <RadioGroup name={RADIO_NAME} small>
26
+ <RadioButton id="banana" />
27
+ <p>foo</p>
28
+ </RadioGroup>
29
+ );
30
+
31
+ const radio = screen.getByRole('radio');
32
+ const radioContainer = radio.parentElement;
33
+ expect(radio).toHaveAttribute('name', RADIO_NAME);
34
+ expect(radioContainer).toHaveClass('ds_radio--small');
35
+ });
36
+
37
+ test('inline radio group', () => {
38
+ render(
39
+ <RadioGroup inline>
40
+ <RadioButton id="banana" />
41
+ </RadioGroup>
42
+ );
43
+
44
+ const radio = screen.getAllByRole('radio')[0];
45
+ const groupContainer = radio.parentElement?.parentElement;
46
+ expect(groupContainer).toHaveClass('ds_field-group--inline');
47
+ });
48
+
49
+ test('passing additional props', () => {
50
+ render(
51
+ <RadioGroup data-test="foo" data-testid="radiogroup"/>
52
+ );
53
+
54
+ const radioGroup = screen.getByTestId('radiogroup');
55
+ expect(radioGroup?.dataset.test).toEqual('foo');
56
+ });
57
+
58
+ test('passing additional CSS classes', () => {
59
+ render(
60
+ <RadioGroup className="foo" data-testid="radiogroup"/>
61
+ );
62
+
63
+ const radioGroup = screen.getByTestId('radiogroup');
64
+ expect(radioGroup).toHaveClass('foo');
65
+ });
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { CheckboxRadioContext } from '../../utils/context';
3
+
4
+ const RadioGroup = ({
5
+ children,
6
+ className,
7
+ inline,
8
+ name,
9
+ small = false,
10
+ ...props
11
+ }: SGDS.Component.RadioButton.Group) => {
12
+ return (
13
+ <div
14
+ className={[
15
+ 'ds_radios',
16
+ 'ds_field-group',
17
+ inline && 'ds_field-group--inline',
18
+ className
19
+ ].join(' ')}
20
+ {...props}
21
+ >
22
+ <CheckboxRadioContext value={{ small, name }}>
23
+ {children}
24
+ </CheckboxRadioContext>
25
+ </div>
26
+ );
27
+ };
28
+
29
+ RadioGroup.displayName = 'RadioGroup';
30
+
31
+ export default RadioGroup;