@scottish-government/designsystem-react 0.3.0-beta.0 → 0.4.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 (55) hide show
  1. package/@types/common/AbstractNotificationBanner.d.ts +17 -0
  2. package/@types/components/Table.d.ts +8 -0
  3. package/@types/components/TaskList.d.ts +1 -1
  4. package/dist/common/abstract-notification-banner.jsx +63 -0
  5. package/dist/components/accordion/accordion.jsx +2 -3
  6. package/dist/components/breadcrumbs/breadcrumbs.jsx +2 -2
  7. package/dist/components/cookie-banner/cookie-banner.jsx +21 -0
  8. package/dist/components/notification-banner/notification-banner.jsx +7 -34
  9. package/dist/components/page-metadata/page-metadata.jsx +2 -3
  10. package/dist/components/table/table.jsx +24 -0
  11. package/dist/components/task-list/task-list.jsx +6 -7
  12. package/dist/tsconfig.tsbuildinfo +1 -1
  13. package/package.json +1 -1
  14. package/src/common/abstract-notification-banner.test.tsx +126 -0
  15. package/src/common/abstract-notification-banner.tsx +87 -0
  16. package/src/common/conditional-wrapper.test.tsx +1 -1
  17. package/src/common/screen-reader-text.test.tsx +1 -1
  18. package/src/common/wrapper-tag.test.tsx +3 -3
  19. package/src/components/accordion/accordion.test.tsx +40 -40
  20. package/src/components/accordion/accordion.tsx +4 -2
  21. package/src/components/aspect-box/aspect-box.test.tsx +7 -7
  22. package/src/components/breadcrumbs/breadcrumbs.tsx +0 -2
  23. package/src/components/checkbox/checkbox.test.tsx +8 -8
  24. package/src/components/confirmation-message/confirmation-message.test.tsx +1 -1
  25. package/src/components/cookie-banner/cookie-banner.test.tsx +25 -0
  26. package/src/components/cookie-banner/cookie-banner.tsx +36 -0
  27. package/src/components/details/details.test.tsx +7 -7
  28. package/src/components/inset-text/inset-text.test.tsx +1 -1
  29. package/src/components/notification-banner/notification-banner.test.tsx +13 -73
  30. package/src/components/notification-banner/notification-banner.tsx +13 -41
  31. package/src/components/notification-panel/notification-panel.test.tsx +6 -6
  32. package/src/components/page-header/page-header.test.tsx +2 -2
  33. package/src/components/page-metadata/page-metadata.test.tsx +12 -12
  34. package/src/components/page-metadata/page-metadata.tsx +4 -2
  35. package/src/components/pagination/pagination.test.tsx +28 -30
  36. package/src/components/phase-banner/phase-banner.test.tsx +8 -8
  37. package/src/components/question/question.test.tsx +3 -3
  38. package/src/components/radio-button/radio-button.test.tsx +7 -7
  39. package/src/components/select/select.test.tsx +9 -9
  40. package/src/components/sequential-navigation/sequential-navigation.test.tsx +4 -4
  41. package/src/components/side-navigation/side-navigation.test.tsx +1 -1
  42. package/src/components/site-header/site-header.test.tsx +22 -22
  43. package/src/components/site-search/site-search.test.tsx +9 -9
  44. package/src/components/skip-links/skip-links.test.tsx +3 -3
  45. package/src/components/summary-card/summary-card.test.tsx +2 -2
  46. package/src/components/summary-list/summary-list.test.tsx +35 -16
  47. package/src/components/table/table.test.tsx +77 -0
  48. package/src/components/table/table.tsx +36 -0
  49. package/src/components/task-list/task-list.test.tsx +81 -83
  50. package/src/components/task-list/task-list.tsx +9 -5
  51. package/src/components/text-input/text-input.test.tsx +6 -6
  52. package/src/components/textarea/textarea.test.tsx +2 -2
  53. package/src/components/warning-text/warning-text.test.tsx +1 -1
  54. package/vitest-setup.ts +1 -1
  55. package/@types/components/NotificationBanner.d.ts +0 -9
@@ -0,0 +1,126 @@
1
+ import { test, expect } from 'vitest';
2
+ import { render, screen, within } from '@testing-library/react';
3
+ import AbstractNotificationBanner from './abstract-notification-banner';
4
+ import Button from '../components/button/button';
5
+
6
+ const text = 'We need to tell you about something';
7
+
8
+ test('abstract notification banner renders correctly', () => {
9
+ render(
10
+ <AbstractNotificationBanner>
11
+ {text}
12
+ </AbstractNotificationBanner>
13
+ );
14
+
15
+ const bannerTitle = screen.getByRole('heading');
16
+ const bannerText = bannerTitle.nextElementSibling;
17
+ const bannerContent = bannerTitle.parentElement;
18
+ const bannerWrapper = bannerContent?.parentElement;
19
+ const bannerContainer = bannerWrapper?.parentElement;
20
+
21
+
22
+ expect(bannerTitle.textContent).toEqual('Information');
23
+ expect(bannerTitle.tagName).toEqual('H2');
24
+ expect(bannerTitle).toHaveClass('visually-hidden');
25
+
26
+ expect(bannerText).toHaveClass('ds_notification__text');
27
+ expect(bannerText?.textContent).toEqual(text);
28
+
29
+ expect(bannerContent).toHaveClass('ds_notification__content');
30
+ expect(bannerWrapper).toHaveClass('ds_wrapper');
31
+ expect(bannerContainer).toHaveClass('ds_notification');
32
+ });
33
+
34
+ test('abstract notification banner with close button', () => {
35
+ render(
36
+ <AbstractNotificationBanner close>
37
+ {text}
38
+ </AbstractNotificationBanner>
39
+ );
40
+
41
+ const bannerTitle = screen.getByRole('heading');
42
+ const bannerContent = bannerTitle.parentElement;
43
+ const closeButton = screen.getByRole('button');
44
+ const closeButtonLabel = within(closeButton).getByText('Close this notification');
45
+ const closeButtonIcon = within(closeButton).getByRole('img', { hidden: true });
46
+
47
+ expect(bannerContent).toHaveClass('ds_notification__content--has-close');
48
+ expect(closeButton).toHaveClass('ds_notification__close', 'js-close-notification');
49
+ expect(closeButton).toHaveAttribute('type', 'button');
50
+
51
+ expect(closeButtonLabel).toBeInTheDocument();
52
+ expect(closeButtonLabel).toHaveClass('visually-hidden');
53
+
54
+ expect(closeButtonIcon).toHaveClass('ds_icon', 'ds_icon--fill');
55
+ });
56
+
57
+ test('abstract notification banner with icon', () => {
58
+ render(
59
+ <AbstractNotificationBanner icon="Search">
60
+ {text}
61
+ </AbstractNotificationBanner>
62
+ );
63
+
64
+ const bannerTitle = screen.getByRole('heading');
65
+ const bannerIconContainer = bannerTitle.nextElementSibling as HTMLElement;
66
+ const bannerIcon = within(bannerIconContainer).getByRole('img', { hidden: true });
67
+
68
+ expect(bannerIconContainer).toHaveClass('ds_notification__icon');
69
+ expect(bannerIcon).toHaveClass('ds_icon');
70
+ expect(bannerIcon).toHaveAttribute('aria-hidden');
71
+ });
72
+
73
+ test('abstract notification banner with icon modifier classes', () => {
74
+ render(
75
+ <AbstractNotificationBanner icon="Search" iconColour iconInverse>
76
+ {text}
77
+ </AbstractNotificationBanner>
78
+ );
79
+
80
+ const bannerTitle = screen.getByRole('heading');
81
+ const bannerIconContainer = bannerTitle.nextElementSibling;
82
+
83
+ expect(bannerIconContainer).toHaveClass('ds_notification__icon', 'ds_notification__icon--inverse', 'ds_notification__icon--colour');
84
+ });
85
+
86
+ test('abstract notification banner with buttons', () => {
87
+ render(
88
+ <AbstractNotificationBanner>
89
+ {text}
90
+ <AbstractNotificationBanner.Buttons>
91
+ <Button data-testid="button">Foo</Button>
92
+ </AbstractNotificationBanner.Buttons>
93
+ </AbstractNotificationBanner>
94
+ );
95
+
96
+ const bannerContainer = document.querySelector('.ds_notification');
97
+ const button = screen.getByTestId('button');
98
+ const buttonContainer = button.parentElement;
99
+ const textContainer = bannerContainer?.querySelector('.ds_notification__text');
100
+
101
+ expect(buttonContainer).toHaveClass('ds_button-group');
102
+ expect(buttonContainer?.tagName).toEqual('DIV');
103
+ expect(buttonContainer?.previousElementSibling).toEqual(textContainer);
104
+ });
105
+
106
+ test('passing additional props', () => {
107
+ render(
108
+ <AbstractNotificationBanner data-test="foo">
109
+ {text}
110
+ </AbstractNotificationBanner>
111
+ )
112
+
113
+ const bannerContainer = document.querySelector('.ds_notification') as HTMLElement;
114
+ expect(bannerContainer?.dataset.test).toEqual('foo');
115
+ });
116
+
117
+ test('passing additional CSS classes', () => {
118
+ render(
119
+ <AbstractNotificationBanner className="foo">
120
+ {text}
121
+ </AbstractNotificationBanner>
122
+ )
123
+
124
+ const bannerContainer = document.querySelector('.ds_notification');
125
+ expect(bannerContainer).toHaveClass('foo', 'ds_notification');
126
+ });
@@ -0,0 +1,87 @@
1
+ import { Children, isValidElement } from 'react';
2
+ import Icon from './icon';
3
+ import ScreenReaderText from './screen-reader-text';
4
+
5
+ const Buttons: React.FC<SGDS.Common.AbstractNotificationBanner.Buttons> = ({
6
+ children
7
+ }) => {
8
+ return (<>{children}</>);
9
+ }
10
+
11
+ const AbstractNotificationBanner: React.FC<SGDS.Common.AbstractNotificationBanner>
12
+ & { Buttons: React.FC<SGDS.Common.AbstractNotificationBanner.Buttons> } = ({
13
+ children,
14
+ className,
15
+ close,
16
+ icon,
17
+ iconColour,
18
+ iconInverse,
19
+ title = 'Information',
20
+ ...props
21
+ }) => {
22
+ let content: any[] = [];
23
+ let buttons;
24
+
25
+ Children.forEach(children, (child) => {
26
+ if (isValidElement(child) && child.type === Buttons) {
27
+ buttons = child;
28
+ } else {
29
+ content.push(child);
30
+ }
31
+ });
32
+
33
+ return (
34
+ <div
35
+ className={[
36
+ 'ds_notification',
37
+ className
38
+ ].join(' ')}
39
+ data-module="ds-notification"
40
+ {...props}
41
+ >
42
+ <div className="ds_wrapper">
43
+ <div className={
44
+ [
45
+ 'ds_notification__content',
46
+ close && 'ds_notification__content--has-close'
47
+ ].join(' ')}
48
+ >
49
+ <h2 className="visually-hidden">{title}</h2>
50
+
51
+ {icon &&
52
+ <span
53
+ className={[
54
+ 'ds_notification__icon',
55
+ iconInverse && 'ds_notification__icon--inverse',
56
+ iconColour && 'ds_notification__icon--colour'
57
+ ].join(' ')} aria-hidden="true">
58
+ <Icon icon={icon} />
59
+ </span>
60
+ }
61
+
62
+ <div className="ds_notification__text">
63
+ {content}
64
+ </div>
65
+
66
+ {close &&
67
+ <button type="button" className="ds_notification__close js-close-notification">
68
+ <ScreenReaderText>Close this notification</ScreenReaderText>
69
+ <Icon fill icon="Close" aria-hidden="true" />
70
+ </button>
71
+ }
72
+
73
+ {buttons &&
74
+ <div className="ds_button-group">
75
+ {buttons}
76
+ </div>
77
+ }
78
+ </div>
79
+ </div>
80
+ </div>
81
+ );
82
+ };
83
+
84
+ AbstractNotificationBanner.displayName = 'AbstractNotificationBanner';
85
+ AbstractNotificationBanner.Buttons = Buttons;
86
+
87
+ export default AbstractNotificationBanner;
@@ -16,7 +16,7 @@ test('conditional wrapper true', () => {
16
16
  const elementParent = screen.getByTestId('wrapper');
17
17
  expect(element).toBeInTheDocument();
18
18
  expect(elementParent).toBeInTheDocument();
19
- expect(element.parentNode).toEqual(elementParent)
19
+ expect(element.parentElement).toEqual(elementParent)
20
20
  });
21
21
 
22
22
  test('conditional wrapper false', () => {
@@ -14,7 +14,7 @@ test('screen reader text renders correctly', () => {
14
14
  const srtext = document.querySelector('span');
15
15
 
16
16
  expect(srtext).toHaveClass('visually-hidden');
17
- expect(srtext.textContent).toEqual(content)
17
+ expect(srtext?.textContent).toEqual(content)
18
18
  });
19
19
 
20
20
  test('passing additional props', () => {
@@ -13,7 +13,7 @@ test('wrapper tag renders correctly', () => {
13
13
 
14
14
  const wrapper = document.querySelector('#foo');
15
15
 
16
- expect(wrapper.tagName).toEqual('DIV');
16
+ expect(wrapper?.tagName).toEqual('DIV');
17
17
  });
18
18
 
19
19
  test('wrapper tag widh tag name', () => {
@@ -27,7 +27,7 @@ test('wrapper tag widh tag name', () => {
27
27
 
28
28
  const wrapper = document.querySelector('#foo');
29
29
 
30
- expect(wrapper.tagName).toEqual('SECTION');
30
+ expect(wrapper?.tagName).toEqual('SECTION');
31
31
  });
32
32
 
33
33
  test('passing additional props', () => {
@@ -37,6 +37,6 @@ test('passing additional props', () => {
37
37
  </WrapperTag>
38
38
  );
39
39
 
40
- const wrapper = document.querySelector('#foo');
40
+ const wrapper = document.querySelector('#foo') as HTMLElement;
41
41
  expect(wrapper?.dataset.test).toEqual('foo');
42
42
  });
@@ -1,6 +1,6 @@
1
1
  import { test, expect } from 'vitest';
2
2
  import { render, screen, within } from '@testing-library/react';
3
- import Accordion, { AccordionItem } from './accordion';
3
+ import Accordion from './accordion';
4
4
 
5
5
  const id = 'my-accordion';
6
6
  const itemId = 'my-accordion-item';
@@ -13,20 +13,20 @@ test('accordion renders correctly', () => {
13
13
 
14
14
  render(
15
15
  <Accordion id={id} data-testid={id}>
16
- <AccordionItem id="accordion-1" title="Healthcare for veterans">
16
+ <Accordion.Item id="accordion-1" title="Healthcare for veterans">
17
17
  <p>Veterans are entitled to the same healthcare as any citizen. And there
18
18
  are health care options and support available specifically for veterans.</p>
19
19
  <p>If you have a health condition that’s related to your service, you’re
20
20
  entitled to priority treatment based on clinical need.</p>
21
- </AccordionItem>
22
- <AccordionItem open id="accordion-2" title="Employability for veterans">
21
+ </Accordion.Item>
22
+ <Accordion.Item open id="accordion-2" title="Employability for veterans">
23
23
  <p>If you&apos;re looking for a job, there are several organisations that can help
24
24
  you <a href="#accordion-link">find a job or develop new skills</a>.</p>
25
- </AccordionItem>
26
- <AccordionItem id="accordion-3" title="Housing for veterans">
25
+ </Accordion.Item>
26
+ <Accordion.Item id="accordion-3" title="Housing for veterans">
27
27
  <p>If you need <a href="#accordion-link">help finding a place to live</a>{' '}
28
28
  there&apos;s support specifically for veterans.</p>
29
- </AccordionItem>
29
+ </Accordion.Item>
30
30
  </Accordion>
31
31
  );
32
32
 
@@ -40,31 +40,31 @@ test('accordion renders correctly', () => {
40
40
 
41
41
  expect(openAllButton).toHaveClass('ds_accordion__open-all', 'ds_link', 'js-open-all');
42
42
  expect(openAllButton).toHaveAttribute('type', 'button');
43
- expect(openAllButton.textContent).toEqual('Open all sections');
44
- expect(openAllButton.innerHTML).toEqual('Open all <span class="visually-hidden">sections</span>');
43
+ expect(openAllButton?.textContent).toEqual('Open all sections');
44
+ expect(openAllButton?.innerHTML).toEqual('Open all <span class="visually-hidden">sections</span>');
45
45
 
46
46
  expect(accordionItems.length).toEqual(3);
47
47
 
48
- expect(firstAccordionTitle.tagName).toEqual(defaultHeaderLevel.toUpperCase());
48
+ expect(firstAccordionTitle?.tagName).toEqual(defaultHeaderLevel.toUpperCase());
49
49
  });
50
50
 
51
51
  test('accordion without open all', () => {
52
52
  render(
53
53
  <Accordion id={id} data-testid={id} hideOpenAll>
54
- <AccordionItem id="accordion-1" title="Healthcare for veterans">
54
+ <Accordion.Item id="accordion-1" title="Healthcare for veterans">
55
55
  <p>Veterans are entitled to the same healthcare as any citizen. And there
56
56
  are health care options and support available specifically for veterans.</p>
57
57
  <p>If you have a health condition that’s related to your service, you’re
58
58
  entitled to priority treatment based on clinical need.</p>
59
- </AccordionItem>
60
- <AccordionItem id="accordion-2" title="Employability for veterans">
59
+ </Accordion.Item>
60
+ <Accordion.Item id="accordion-2" title="Employability for veterans">
61
61
  <p>If you&apos;re looking for a job, there are several organisations that can help
62
62
  you <a href="#accordion-link">find a job or develop new skills</a>.</p>
63
- </AccordionItem>
64
- <AccordionItem id="accordion-3" title="Housing for veterans">
63
+ </Accordion.Item>
64
+ <Accordion.Item id="accordion-3" title="Housing for veterans">
65
65
  <p>If you need <a href="#accordion-link">help finding a place to live</a>{' '}
66
66
  there&apos;s support specifically for veterans.</p>
67
- </AccordionItem>
67
+ </Accordion.Item>
68
68
  </Accordion>
69
69
  );
70
70
 
@@ -89,12 +89,12 @@ test('accordion with custom header level', () => {
89
89
 
90
90
  render(
91
91
  <Accordion id={id} data-testid={id} headerLevel={headerLevel}>
92
- <AccordionItem id="accordion-1" title="Healthcare for veterans">
92
+ <Accordion.Item id="accordion-1" title="Healthcare for veterans">
93
93
  <p>Veterans are entitled to the same healthcare as any citizen. And there
94
94
  are health care options and support available specifically for veterans.</p>
95
95
  <p>If you have a health condition that’s related to your service, you’re
96
96
  entitled to priority treatment based on clinical need.</p>
97
- </AccordionItem>
97
+ </Accordion.Item>
98
98
  </Accordion>
99
99
  );
100
100
 
@@ -124,9 +124,9 @@ test('passing additional CSS classes', () => {
124
124
 
125
125
  test('accordion item renders correctly', () => {
126
126
  render(
127
- <AccordionItem id={itemId} data-testid={itemId} title={titleText}>
127
+ <Accordion.Item id={itemId} data-testid={itemId} title={titleText}>
128
128
  <p>{contentText}</p>
129
- </AccordionItem>
129
+ </Accordion.Item>
130
130
  );
131
131
 
132
132
  const accordionItem = screen.getByTestId(itemId);
@@ -134,7 +134,7 @@ test('accordion item renders correctly', () => {
134
134
  const header = document.querySelector('.ds_accordion-item__header');
135
135
  const title = header?.querySelector('.ds_accordion-item__title');
136
136
  const indicator = header?.querySelector('.ds_accordion-item__indicator');
137
- const label = header.querySelector('.ds_accordion-item__label');
137
+ const label = header?.querySelector('.ds_accordion-item__label');
138
138
  const body = document.querySelector('.ds_accordion-item__body');
139
139
 
140
140
  expect(accordionItem).toHaveClass('ds_accordion-item');
@@ -143,39 +143,39 @@ test('accordion item renders correctly', () => {
143
143
  expect(input).toHaveClass('ds_accordion-item__control', 'visually-hidden')
144
144
  expect(input).toHaveAttribute('id', `${itemId}-control`);
145
145
 
146
- expect(header.tagName).toEqual('DIV');
146
+ expect(header?.tagName).toEqual('DIV');
147
147
 
148
148
  expect(title).toHaveAttribute('id', `panel-${itemId}-heading`);
149
- expect(title.tagName).toEqual('H3');
150
- expect(title.textContent).toEqual(titleText);
149
+ expect(title?.tagName).toEqual('H3');
150
+ expect(title?.textContent).toEqual(titleText);
151
151
 
152
- expect(indicator.tagName).toEqual('SPAN');
152
+ expect(indicator?.tagName).toEqual('SPAN');
153
153
 
154
154
  expect(label).toHaveAttribute('for', input.id);
155
- expect(label.tagName).toEqual('LABEL');
156
- expect(label.textContent).toEqual('Show this section');
155
+ expect(label?.tagName).toEqual('LABEL');
156
+ expect(label?.textContent).toEqual('Show this section');
157
157
  expect(label?.children[0]).toHaveClass('visually-hidden');
158
158
 
159
- expect(body.innerHTML).toEqual(`<p>${contentText}</p>`);
159
+ expect(body?.innerHTML).toEqual(`<p>${contentText}</p>`);
160
160
  });
161
161
 
162
162
  test('accordion items without ID are given unique IDs', () => {
163
163
  render(
164
164
  <Accordion id={id} data-testid={id} hideOpenAll>
165
- <AccordionItem data-testid="item1" title="Healthcare for veterans">
165
+ <Accordion.Item data-testid="item1" title="Healthcare for veterans">
166
166
  <p>Veterans are entitled to the same healthcare as any citizen. And there
167
167
  are health care options and support available specifically for veterans.</p>
168
168
  <p>If you have a health condition that’s related to your service, you’re
169
169
  entitled to priority treatment based on clinical need.</p>
170
- </AccordionItem>
171
- <AccordionItem data-testid="item2" title="Employability for veterans">
170
+ </Accordion.Item>
171
+ <Accordion.Item data-testid="item2" title="Employability for veterans">
172
172
  <p>If you&apos;re looking for a job, there are several organisations that can help
173
173
  you <a href="#accordion-link">find a job or develop new skills</a>.</p>
174
- </AccordionItem>
175
- <AccordionItem data-testid="item3" title="Housing for veterans">
174
+ </Accordion.Item>
175
+ <Accordion.Item data-testid="item3" title="Housing for veterans">
176
176
  <p>If you need <a href="#accordion-link">help finding a place to live</a>{' '}
177
177
  there&apos;s support specifically for veterans.</p>
178
- </AccordionItem>
178
+ </Accordion.Item>
179
179
  </Accordion>
180
180
  );
181
181
 
@@ -194,9 +194,9 @@ test('accordion items without ID are given unique IDs', () => {
194
194
 
195
195
  test('open accordion item', () => {
196
196
  render(
197
- <AccordionItem open id={itemId} data-testid={itemId} title={titleText}>
197
+ <Accordion.Item open id={itemId} data-testid={itemId} title={titleText}>
198
198
  <p>{contentText}</p>
199
- </AccordionItem>
199
+ </Accordion.Item>
200
200
  );
201
201
 
202
202
  const accordionItem = screen.getByTestId(itemId);
@@ -207,12 +207,12 @@ test('open accordion item', () => {
207
207
 
208
208
  test('passing additional props to accordion item', () => {
209
209
  render(
210
- <AccordionItem id={itemId} data-testid={itemId} title="Healthcare for veterans" data-test="foo">
210
+ <Accordion.Item id={itemId} data-testid={itemId} title="Healthcare for veterans" data-test="foo">
211
211
  <p>Veterans are entitled to the same healthcare as any citizen. And there
212
212
  are health care options and support available specifically for veterans.</p>
213
213
  <p>If you have a health condition that’s related to your service, you’re
214
214
  entitled to priority treatment based on clinical need.</p>
215
- </AccordionItem>
215
+ </Accordion.Item>
216
216
  );
217
217
 
218
218
  const accordionItem = screen.getByTestId(itemId);
@@ -221,12 +221,12 @@ test('passing additional props to accordion item', () => {
221
221
 
222
222
  test('passing additional CSS classes', () => {
223
223
  render(
224
- <AccordionItem id={itemId} data-testid={itemId} title="Healthcare for veterans" className="foo">
224
+ <Accordion.Item id={itemId} data-testid={itemId} title="Healthcare for veterans" className="foo">
225
225
  <p>Veterans are entitled to the same healthcare as any citizen. And there
226
226
  are health care options and support available specifically for veterans.</p>
227
227
  <p>If you have a health condition that’s related to your service, you’re
228
228
  entitled to priority treatment based on clinical need.</p>
229
- </AccordionItem>
229
+ </Accordion.Item>
230
230
  );
231
231
 
232
232
  const accordionItem = screen.getByTestId(itemId);
@@ -5,7 +5,7 @@ import DSAccordion from '@scottish-government/design-system/src/components/accor
5
5
 
6
6
  let accordionItemCounter = 0;
7
7
 
8
- export const AccordionItem: React.FC<SGDS.Component.Accordion.Item> = ({
8
+ const AccordionItem: React.FC<SGDS.Component.Accordion.Item> = ({
9
9
  children,
10
10
  className,
11
11
  headerLevel = 'h3',
@@ -58,7 +58,8 @@ export const AccordionItem: React.FC<SGDS.Component.Accordion.Item> = ({
58
58
  );
59
59
  };
60
60
 
61
- const Accordion: React.FC<SGDS.Component.Accordion> = ({
61
+ const Accordion: React.FC<SGDS.Component.Accordion>
62
+ & { Item: React.FC<SGDS.Component.Accordion.Item> } = ({
62
63
  children,
63
64
  className,
64
65
  headerLevel = 'h3',
@@ -112,5 +113,6 @@ const Accordion: React.FC<SGDS.Component.Accordion> = ({
112
113
 
113
114
  Accordion.displayName = 'Accordion';
114
115
  AccordionItem.displayName = 'AccordionItem';
116
+ Accordion.Item = AccordionItem;
115
117
 
116
118
  export default Accordion;
@@ -10,7 +10,7 @@ test('aspect box renders correctly', () => {
10
10
  );
11
11
 
12
12
  const image = document.querySelector('img');
13
- const imageContainer = image?.parentNode;
13
+ const imageContainer = image?.parentElement;
14
14
 
15
15
  expect(image).toHaveClass('ds_aspect-box__inner');
16
16
  expect(imageContainer).toHaveClass('ds_aspect-box');
@@ -24,7 +24,7 @@ test('1:1 ratio', () => {
24
24
  );
25
25
 
26
26
  const image = document.querySelector('img');
27
- const imageContainer = image?.parentNode;
27
+ const imageContainer = image?.parentElement;
28
28
 
29
29
  expect(imageContainer).toHaveClass('ds_aspect-box--square');
30
30
  });
@@ -37,7 +37,7 @@ test('square ratio', () => {
37
37
  );
38
38
 
39
39
  const image = document.querySelector('img');
40
- const imageContainer = image?.parentNode;
40
+ const imageContainer = image?.parentElement;
41
41
 
42
42
  expect(imageContainer).toHaveClass('ds_aspect-box--square');
43
43
  });
@@ -50,7 +50,7 @@ test('4:3 ratio', () => {
50
50
  );
51
51
 
52
52
  const image = document.querySelector('img');
53
- const imageContainer = image?.parentNode;
53
+ const imageContainer = image?.parentElement;
54
54
 
55
55
  expect(imageContainer).toHaveClass('ds_aspect-box--43');
56
56
  });
@@ -63,7 +63,7 @@ test('21:9 ratio', () => {
63
63
  );
64
64
 
65
65
  const image = document.querySelector('img');
66
- const imageContainer = image?.parentNode;
66
+ const imageContainer = image?.parentElement;
67
67
 
68
68
  expect(imageContainer).toHaveClass('ds_aspect-box--219');
69
69
  });
@@ -76,7 +76,7 @@ test('passing additional props', () => {
76
76
  );
77
77
 
78
78
  const image = document.querySelector('img');
79
- const imageContainer = image?.parentNode;
79
+ const imageContainer = image?.parentElement;
80
80
  expect(imageContainer?.dataset.test).toEqual('foo');
81
81
  });
82
82
 
@@ -88,6 +88,6 @@ test('passing additional CSS classes', () => {
88
88
  );
89
89
 
90
90
  const image = document.querySelector('img');
91
- const imageContainer = image?.parentNode;
91
+ const imageContainer = image?.parentElement;
92
92
  expect(imageContainer).toHaveClass('foo', 'ds_aspect-box');
93
93
  });
@@ -25,7 +25,6 @@ const Breadcrumb: React.FC<SGDS.Component.Breadcrumbs.Item> = ({
25
25
  * @returns {JSX.Element} - The element
26
26
  */
27
27
  const Breadcrumbs: React.FC<SGDS.Component.Breadcrumbs> = ({
28
- className,
29
28
  hideLastItem,
30
29
  items,
31
30
  ...props
@@ -33,7 +32,6 @@ const Breadcrumbs: React.FC<SGDS.Component.Breadcrumbs> = ({
33
32
  return (
34
33
  <nav
35
34
  aria-label="Breadcrumb"
36
- className={className}
37
35
  {...props}
38
36
  >
39
37
  <ol className="ds_breadcrumbs">
@@ -29,7 +29,7 @@ test('checkbox group renders correct children', () => {
29
29
  );
30
30
 
31
31
  const checkboxes = screen.getAllByRole('checkbox');
32
- const groupContainer = checkboxes[0].parentNode.parentNode;
32
+ const groupContainer = checkboxes[0].parentElement?.parentElement;
33
33
  expect(checkboxes.length).toEqual(items.length);
34
34
  expect(groupContainer).toHaveClass('ds_checkboxes', 'ds_field-group');
35
35
  });
@@ -54,7 +54,7 @@ test('checkbox group passes all expected item params', () => {
54
54
  );
55
55
 
56
56
  const checkbox = screen.getByRole('checkbox');
57
- const checkboxContainer = checkbox.parentNode;
57
+ const checkboxContainer = checkbox.parentElement;
58
58
  const hintText = screen.getByText('hint text');
59
59
 
60
60
  expect(checkbox).toHaveAttribute('data-behaviour', 'exclusive');
@@ -77,7 +77,7 @@ test('individual checkbox renders correctly', () => {
77
77
  );
78
78
 
79
79
  const checkbox = screen.getByRole('checkbox');
80
- const checkboxContainer = checkbox.parentNode;
80
+ const checkboxContainer = checkbox.parentElement;
81
81
  const label = screen.getByText('Pension Credit');
82
82
 
83
83
  expect(checkboxContainer).toHaveClass('ds_checkbox');
@@ -107,12 +107,12 @@ test('exclusive checkbox', () => {
107
107
  );
108
108
 
109
109
  const checkbox = screen.getByRole('checkbox');
110
- const separator = checkbox.parentNode?.previousSibling;
110
+ const separator = checkbox.parentElement?.previousSibling;
111
111
 
112
112
  expect(checkbox).toHaveAttribute('data-behaviour', 'exclusive');
113
113
  expect(separator).toBeInTheDocument();
114
114
  expect(separator).toHaveClass('ds_checkbox-separator');
115
- expect(separator.textContent).toEqual('or');
115
+ expect(separator?.textContent).toEqual('or');
116
116
  });
117
117
 
118
118
  test('checkbox with blur fn', () => {
@@ -161,7 +161,7 @@ test('small checkbox', () => {
161
161
  );
162
162
 
163
163
  const checkbox = screen.getByRole('checkbox');
164
- const checkboxContainer = checkbox.parentNode;
164
+ const checkboxContainer = checkbox.parentElement;
165
165
 
166
166
  expect(checkboxContainer).toHaveClass('ds_checkbox--small');
167
167
  });
@@ -175,7 +175,7 @@ test('passing additional props', () => {
175
175
  );
176
176
 
177
177
  const checkboxes = screen.getAllByRole('checkbox');
178
- const groupContainer = checkboxes[0]?.parentNode?.parentNode;
178
+ const groupContainer = checkboxes[0]?.parentElement?.parentElement;
179
179
  expect(groupContainer?.dataset.test).toEqual('foo');
180
180
  });
181
181
 
@@ -188,6 +188,6 @@ test('passing additional CSS classes', () => {
188
188
  );
189
189
 
190
190
  const checkboxes = screen.getAllByRole('checkbox');
191
- const groupContainer = checkboxes[0]?.parentNode?.parentNode;
191
+ const groupContainer = checkboxes[0]?.parentElement?.parentElement;
192
192
  expect(groupContainer).toHaveClass('foo', 'ds_checkboxes');
193
193
  });
@@ -52,7 +52,7 @@ test('passing additional props', () => {
52
52
  </ConfirmationMessage>
53
53
  );
54
54
 
55
- const container = document.querySelector('.ds_confirmation-message');
55
+ const container = document.querySelector('.ds_confirmation-message') as HTMLElement;
56
56
  expect(container?.dataset.test).toEqual('foo');
57
57
  });
58
58