@scottish-government/designsystem-react 0.1.0 → 0.1.2

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 (90) hide show
  1. package/@types/components/InsetText.d.ts +5 -0
  2. package/@types/components/WarningText.d.ts +5 -0
  3. package/README.md +26 -0
  4. package/dist/components/accordion/accordion.jsx +10 -4
  5. package/dist/components/aspect-box/aspect-box.jsx +3 -2
  6. package/dist/components/back-to-top/back-to-top.jsx +5 -2
  7. package/dist/components/breadcrumbs/breadcrumbs.jsx +2 -2
  8. package/dist/components/button/button.jsx +3 -2
  9. package/dist/components/checkbox/checkbox.jsx +6 -2
  10. package/dist/components/confirmation-message/confirmation-message.jsx +5 -2
  11. package/dist/components/contents-nav/contents-nav.jsx +6 -3
  12. package/dist/components/date-picker/date-picker.jsx +3 -2
  13. package/dist/components/details/details.jsx +2 -1
  14. package/dist/components/error-message/error-message.jsx +2 -1
  15. package/dist/components/inset-text/inset-text.jsx +5 -2
  16. package/dist/components/notification-banner/notification-banner.jsx +6 -2
  17. package/dist/components/notification-panel/notification-panel.jsx +5 -2
  18. package/dist/components/page-header/page-header.jsx +5 -2
  19. package/dist/components/page-metadata/page-metadata.jsx +7 -3
  20. package/dist/components/phase-banner/phase-banner.jsx +5 -2
  21. package/dist/components/question/question.jsx +3 -2
  22. package/dist/components/radio-button/radio-button.jsx +3 -2
  23. package/dist/components/select/select.jsx +2 -1
  24. package/dist/components/sequential-navigation/sequential-navigation.jsx +5 -2
  25. package/dist/components/side-navigation/side-navigation.jsx +5 -2
  26. package/dist/components/site-navigation/site-navigation.jsx +5 -2
  27. package/dist/components/site-search/site-search.jsx +3 -2
  28. package/dist/components/task-list/task-list.jsx +13 -7
  29. package/dist/components/textarea/textarea.jsx +2 -1
  30. package/dist/components/warning-text/warning-text.jsx +5 -2
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +1 -1
  33. package/src/common/icon.test.tsx +1 -1
  34. package/src/components/accordion/accordion.test.tsx +25 -1
  35. package/src/components/accordion/accordion.tsx +10 -2
  36. package/src/components/aspect-box/aspect-box.test.tsx +12 -0
  37. package/src/components/aspect-box/aspect-box.tsx +3 -1
  38. package/src/components/back-to-top/back-to-top.test.tsx +10 -0
  39. package/src/components/back-to-top/back-to-top.tsx +5 -1
  40. package/src/components/breadcrumbs/breadcrumbs.test.tsx +12 -0
  41. package/src/components/breadcrumbs/breadcrumbs.tsx +2 -0
  42. package/src/components/button/button.test.tsx +9 -0
  43. package/src/components/button/button.tsx +4 -2
  44. package/src/components/checkbox/checkbox.test.tsx +13 -0
  45. package/src/components/checkbox/checkbox.tsx +6 -1
  46. package/src/components/confirmation-message/confirmation-message.test.tsx +22 -0
  47. package/src/components/confirmation-message/confirmation-message.tsx +8 -2
  48. package/src/components/contents-nav/contents-nav.test.tsx +13 -0
  49. package/src/components/contents-nav/contents-nav.tsx +8 -4
  50. package/src/components/date-picker/date-picker.test.tsx +13 -0
  51. package/src/components/date-picker/date-picker.tsx +4 -2
  52. package/src/components/details/details.test.tsx +12 -0
  53. package/src/components/details/details.tsx +2 -0
  54. package/src/components/error-message/error-message.test.tsx +9 -0
  55. package/src/components/error-message/error-message.tsx +2 -0
  56. package/src/components/inset-text/inset-text.test.tsx +11 -0
  57. package/src/components/inset-text/inset-text.tsx +6 -2
  58. package/src/components/notification-banner/notification-banner.test.tsx +11 -0
  59. package/src/components/notification-banner/notification-banner.tsx +6 -1
  60. package/src/components/notification-panel/notification-panel.test.tsx +12 -0
  61. package/src/components/notification-panel/notification-panel.tsx +5 -1
  62. package/src/components/page-header/page-header.test.tsx +9 -0
  63. package/src/components/page-header/page-header.tsx +5 -1
  64. package/src/components/page-metadata/page-metadata.test.tsx +15 -0
  65. package/src/components/page-metadata/page-metadata.tsx +7 -1
  66. package/src/components/phase-banner/phase-banner.test.tsx +11 -0
  67. package/src/components/phase-banner/phase-banner.tsx +5 -1
  68. package/src/components/question/question.test.tsx +10 -0
  69. package/src/components/question/question.tsx +3 -1
  70. package/src/components/radio-button/radio-button.test.tsx +13 -0
  71. package/src/components/radio-button/radio-button.tsx +3 -1
  72. package/src/components/select/select.test.tsx +15 -0
  73. package/src/components/select/select.tsx +2 -0
  74. package/src/components/sequential-navigation/sequential-navigation.test.tsx +13 -0
  75. package/src/components/sequential-navigation/sequential-navigation.tsx +5 -1
  76. package/src/components/side-navigation/side-navigation.test.tsx +18 -0
  77. package/src/components/side-navigation/side-navigation.tsx +5 -1
  78. package/src/components/site-navigation/site-navigation.test.tsx +9 -0
  79. package/src/components/site-navigation/site-navigation.tsx +5 -1
  80. package/src/components/site-search/site-search.test.tsx +10 -0
  81. package/src/components/site-search/site-search.tsx +3 -1
  82. package/src/components/tag/tag.test.tsx +7 -7
  83. package/src/components/task-list/task-list.test.tsx +46 -0
  84. package/src/components/task-list/task-list.tsx +18 -5
  85. package/src/components/text-input/text-input.test.tsx +13 -0
  86. package/src/components/textarea/textarea.test.tsx +13 -0
  87. package/src/components/textarea/textarea.tsx +2 -0
  88. package/src/components/warning-text/warning-text.test.tsx +11 -0
  89. package/src/components/warning-text/warning-text.tsx +6 -2
  90. package/.editorconfig +0 -12
@@ -1,5 +1,6 @@
1
1
  const ErrorMessage: React.FC<SGDS.Component.ErrorMessage> = ({
2
2
  children,
3
+ className,
3
4
  id,
4
5
  text,
5
6
  ...props
@@ -8,6 +9,7 @@ const ErrorMessage: React.FC<SGDS.Component.ErrorMessage> = ({
8
9
  <p
9
10
  className={[
10
11
  'ds_question__error-message',
12
+ className
11
13
  ].join(' ')}
12
14
  dangerouslySetInnerHTML={text ? { __html: text } : undefined}
13
15
  id={id}
@@ -31,3 +31,14 @@ test('passing additional props', () => {
31
31
  const insetTextOuter = document.querySelector('.ds_inset-text');
32
32
  expect(insetTextOuter?.dataset.test).toEqual('foo');
33
33
  });
34
+
35
+ test('passing additional CSS classes', () => {
36
+ render(
37
+ <InsetText className="foo">
38
+ {text}
39
+ </InsetText>
40
+ )
41
+
42
+ const insetTextOuter = document.querySelector('.ds_inset-text');
43
+ expect(insetTextOuter).toHaveClass('foo', 'ds_inset-text');
44
+ });
@@ -1,10 +1,14 @@
1
- const InsetText: React.FC<React.PropsWithChildren> = ({
1
+ const InsetText: React.FC<SGDS.Component.InsetText> = ({
2
2
  children,
3
+ className,
3
4
  ...props
4
5
  }) => {
5
6
  return (
6
7
  <div
7
- className="ds_inset-text"
8
+ className={[
9
+ 'ds_inset-text',
10
+ className
11
+ ].join(' ')}
8
12
  {...props}
9
13
  >
10
14
  <div className="ds_inset-text__text">
@@ -91,3 +91,14 @@ test('passing additional props', () => {
91
91
  const bannerContainer = document.querySelector('.ds_notification');
92
92
  expect(bannerContainer?.dataset.test).toEqual('foo');
93
93
  });
94
+
95
+ test('passing additional CSS classes', () => {
96
+ render(
97
+ <NotificationBanner className="foo">
98
+ {text}
99
+ </NotificationBanner>
100
+ )
101
+
102
+ const bannerContainer = document.querySelector('.ds_notification');
103
+ expect(bannerContainer).toHaveClass('foo', 'ds_notification');
104
+ });
@@ -7,6 +7,7 @@ import ScreenReaderText from '../../common/screen-reader-text';
7
7
 
8
8
  const NotificationBanner: React.FC<SGDS.Component.NotificationBanner> = ({
9
9
  children,
10
+ className,
10
11
  close,
11
12
  icon,
12
13
  iconColour,
@@ -24,7 +25,11 @@ const NotificationBanner: React.FC<SGDS.Component.NotificationBanner> = ({
24
25
 
25
26
  return (
26
27
  <div
27
- className="ds_notification ds_reversed"
28
+ className={[
29
+ 'ds_notification',
30
+ 'ds_reversed',
31
+ className
32
+ ].join(' ')}
28
33
  data-module="ds-notification"
29
34
  ref={ref}
30
35
  {...props}
@@ -75,3 +75,15 @@ test('passing additional props', () => {
75
75
  const notificationPanel = notificationPanelHeading.parentNode;
76
76
  expect(notificationPanel?.dataset.test).toEqual('foo');
77
77
  });
78
+
79
+ test('passing additional CSS classes', () => {
80
+ render(
81
+ <NotificationPanel title={headingText} className="foo">
82
+ {text}
83
+ </NotificationPanel>
84
+ )
85
+
86
+ const notificationPanelHeading = screen.getByRole('heading');
87
+ const notificationPanel = notificationPanelHeading.parentNode;
88
+ expect(notificationPanel).toHaveClass('foo', 'ds_notification-panel');
89
+ });
@@ -3,6 +3,7 @@ import WrapperTag from '../../common/wrapper-tag';
3
3
  const NotificationPanel: React.FC<SGDS.Component.NotificationPanel> = function ({
4
4
  ariaLive,
5
5
  children,
6
+ className,
6
7
  headerLevel = 'h1',
7
8
  title,
8
9
  ...props
@@ -10,7 +11,10 @@ const NotificationPanel: React.FC<SGDS.Component.NotificationPanel> = function (
10
11
  return (
11
12
  <div
12
13
  aria-live={ariaLive}
13
- className="ds_notification-panel"
14
+ className={[
15
+ 'ds_notification-panel',
16
+ className
17
+ ].join(' ')}
14
18
  {...props}
15
19
  >
16
20
  <WrapperTag
@@ -46,3 +46,12 @@ test('passing additional props', () => {
46
46
  const header = screen.getByRole('banner');
47
47
  expect(header?.dataset.test).toEqual('foo');
48
48
  });
49
+
50
+ test('passing additional CSS classes', () => {
51
+ render(
52
+ <PageHeader className="foo" label={labelText} title={titleText}/>
53
+ )
54
+
55
+ const header = screen.getByRole('banner');
56
+ expect(header).toHaveClass('foo', 'ds_page-header');
57
+ });
@@ -1,12 +1,16 @@
1
1
  const PageHeader: React.FC<SGDS.Component.PageHeader> = ({
2
2
  children,
3
+ className,
3
4
  label,
4
5
  title,
5
6
  ...props
6
7
  }) => {
7
8
  return (
8
9
  <header
9
- className="ds_page-header"
10
+ className={[
11
+ 'ds_page-header',
12
+ className
13
+ ].join(' ')}
10
14
  {...props}
11
15
  >
12
16
  {label && <span className="ds_page-header__label ds_content-label">{label}</span>}
@@ -54,3 +54,18 @@ test('passing additional props', () => {
54
54
  expect(metadata?.dataset.test).toEqual('foo');
55
55
  expect(metadataItem?.dataset.test).toEqual('bar');
56
56
  });
57
+
58
+ test('passing additional CSS classes', () => {
59
+ render(
60
+ <Metadata className="foo">
61
+ <MetadataItem className="bar" name="Last updated">
62
+ 21/04/2020
63
+ </MetadataItem>
64
+ </Metadata>
65
+ )
66
+
67
+ const metadata = document.querySelector('.ds_metadata');
68
+ const metadataItem = document.querySelector('.ds_metadata__item');
69
+ expect(metadata).toHaveClass('foo');
70
+ expect(metadataItem).toHaveClass('bar');
71
+ });
@@ -1,10 +1,14 @@
1
1
  export const MetadataItem: React.FC<SGDS.Component.Metadata.Item> = ({
2
2
  children,
3
+ className,
3
4
  name,
4
5
  ...props
5
6
  }) => {
6
7
  return (
7
- <div className="ds_metadata__item"
8
+ <div className={[
9
+ 'ds_metadata__item',
10
+ className
11
+ ].join(' ')}
8
12
  {...props}
9
13
  >
10
14
  <dt className="ds_metadata__key">{name}</dt>{' '}
@@ -17,6 +21,7 @@ export const MetadataItem: React.FC<SGDS.Component.Metadata.Item> = ({
17
21
 
18
22
  const Metadata: React.FC<SGDS.Component.Metadata> = ({
19
23
  children,
24
+ className,
20
25
  inline,
21
26
  ...props
22
27
  }) => {
@@ -25,6 +30,7 @@ const Metadata: React.FC<SGDS.Component.Metadata> = ({
25
30
  className={[
26
31
  'ds_metadata',
27
32
  inline && 'ds_metadata--inline',
33
+ className
28
34
  ].join(' ')}
29
35
  {...props}
30
36
  >
@@ -65,3 +65,14 @@ test('passing additional props', () => {
65
65
  const phaseBanner = document.querySelector('.ds_phase-banner');
66
66
  expect(phaseBanner?.dataset.test).toEqual('foo');
67
67
  });
68
+
69
+ test('passing additional CSS classes', () => {
70
+ render(
71
+ <PhaseBanner className="foo">
72
+ This is a new service. Your <a href="#feedback">feedback</a> will help us to improve it.
73
+ </PhaseBanner>
74
+ )
75
+
76
+ const phaseBanner = document.querySelector('.ds_phase-banner');
77
+ expect(phaseBanner).toHaveClass('foo', 'ds_phase-banner');
78
+ });
@@ -2,12 +2,16 @@ import Tag from "../tag/tag";
2
2
 
3
3
  const PhaseBanner: React.FC<SGDS.Component.PhaseBanner> = ({
4
4
  children,
5
+ className,
5
6
  phaseName,
6
7
  ...props
7
8
  }) => {
8
9
  return (
9
10
  <div
10
- className="ds_phase-banner"
11
+ className={[
12
+ 'ds_phase-banner',
13
+ className
14
+ ].join(' ')}
11
15
  {...props}
12
16
  >
13
17
  <div className="ds_wrapper">
@@ -67,3 +67,13 @@ test('passing additional props', () => {
67
67
  const questionElement = document.querySelector('.ds_question');
68
68
  expect(questionElement?.dataset.test).toEqual('foo');
69
69
  });
70
+
71
+ test('passing additional CSS classes', () => {
72
+ render(
73
+ <Question className="foo">
74
+ </Question>
75
+ )
76
+
77
+ const questionElement = document.querySelector('.ds_question');
78
+ expect(questionElement).toHaveClass('foo', 'ds_question');
79
+ });
@@ -4,6 +4,7 @@ import WrapperTag from '../../common/wrapper-tag';
4
4
 
5
5
  const Question: React.FC<SGDS.Component.Question> = function ({
6
6
  children,
7
+ className,
7
8
  error,
8
9
  errorMessage,
9
10
  hintText,
@@ -16,7 +17,8 @@ const Question: React.FC<SGDS.Component.Question> = function ({
16
17
  tagName={tagName}
17
18
  className={[
18
19
  'ds_question',
19
- error && 'ds_question--error'
20
+ error && 'ds_question--error',
21
+ className
20
22
  ].join(' ')}
21
23
  {...props}
22
24
  >
@@ -188,3 +188,16 @@ test('passing additional props', () => {
188
188
  const groupContainer = radios[0]?.parentNode?.parentNode;
189
189
  expect(groupContainer?.dataset.test).toEqual('foo');
190
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]?.parentNode?.parentNode;
202
+ expect(groupContainer).toHaveClass('foo', 'ds_radios');
203
+ });
@@ -49,6 +49,7 @@ export const Radio: React.FC<SGDS.Component.RadioButton> = ({
49
49
  };
50
50
 
51
51
  const RadioGroup: React.FC<SGDS.Component.RadioButton.Group> = ({
52
+ className,
52
53
  inline,
53
54
  items,
54
55
  name,
@@ -60,7 +61,8 @@ const RadioGroup: React.FC<SGDS.Component.RadioButton.Group> = ({
60
61
  className={[
61
62
  'ds_radios',
62
63
  'ds_field-group',
63
- inline && 'ds_field-group--inline'
64
+ inline && 'ds_field-group--inline',
65
+ className
64
66
  ].join(' ')}
65
67
  {...props}
66
68
  >
@@ -206,3 +206,18 @@ test('passing additional props', () => {
206
206
  const selectWrapper = select.parentNode;
207
207
  expect(selectWrapper?.dataset.test).toEqual('foo');
208
208
  });
209
+
210
+ test('passing additional CSS classes', () => {
211
+ render(
212
+ <Select
213
+ id={id}
214
+ label={labelText}
215
+ options={options}
216
+ className="foo"
217
+ />
218
+ );
219
+
220
+ const select = screen.getByRole('combobox');
221
+ const selectWrapper = select.parentNode;
222
+ expect(selectWrapper).toHaveClass('foo', 'ds_select-wrapper');
223
+ });
@@ -11,6 +11,7 @@ const Option: React.FC<SGDS.Component.Select.Option> = function ({
11
11
  };
12
12
 
13
13
  const Select: React.FC<SGDS.Component.Select> = function ({
14
+ className,
14
15
  defaultValue,
15
16
  error,
16
17
  errorMessage,
@@ -54,6 +55,7 @@ const Select: React.FC<SGDS.Component.Select> = function ({
54
55
  "ds_select-wrapper",
55
56
  error && 'ds_input--error',
56
57
  width && `ds_input--${width}`,
58
+ className
57
59
  ].join(' ')}
58
60
  {...props}
59
61
  >
@@ -65,3 +65,16 @@ test('passing additional props', () => {
65
65
  const sequentialNavigation = screen.getByRole('navigation');
66
66
  expect(sequentialNavigation?.dataset.test).toEqual('foo');
67
67
  });
68
+
69
+ test('passing additional CSS classes', () => {
70
+ render(
71
+ <SequentialNavigation
72
+ className="foo"
73
+ next={nextLinkObj}
74
+ previous={prevLinkObj}
75
+ />
76
+ );
77
+
78
+ const sequentialNavigation = screen.getByRole('navigation');
79
+ expect(sequentialNavigation).toHaveClass('foo', 'ds_sequential-nav');
80
+ });
@@ -34,13 +34,17 @@ const PrevLink: React.FC<SGDS.Component.SequentialNavigation.Link> = ({
34
34
 
35
35
  const SequentialNavigation: React.FC<SGDS.Component.SequentialNavigation> = ({
36
36
  ariaLabel = 'Article navigation',
37
+ className,
37
38
  next,
38
39
  previous,
39
40
  ...props
40
41
  }) => {
41
42
  return (
42
43
  <nav
43
- className="ds_sequential-nav"
44
+ className={[
45
+ 'ds_sequential-nav',
46
+ className
47
+ ].join(' ')}
44
48
  aria-label={ariaLabel}
45
49
  {...props}
46
50
  >
@@ -154,3 +154,21 @@ test('side nav list renders correctly', () => {
154
154
  expect(link).toHaveAttribute('href', '#bramley');
155
155
  expect(link.textContent).toEqual('Bramley');
156
156
  });
157
+
158
+ test('passing additional props', () => {
159
+ render(
160
+ <SideNavigation data-test="foo" items={items} />
161
+ );
162
+
163
+ const sideNavigation = screen.getByRole('navigation');
164
+ expect(sideNavigation?.dataset.test).toEqual('foo');
165
+ });
166
+
167
+ test('passing additional CSS classes', () => {
168
+ render(
169
+ <SideNavigation className="foo" items={items} />
170
+ );
171
+
172
+ const sideNavigation = screen.getByRole('navigation');
173
+ expect(sideNavigation).toHaveClass('foo', 'ds_side-navigation');
174
+ });
@@ -48,6 +48,7 @@ export const Link: React.FC<SGDS.Component.SideNavigation.Link> = function ({
48
48
 
49
49
  const SideNavigation: React.FC<SGDS.Component.SideNavigation> = function ({
50
50
  children,
51
+ className,
51
52
  items,
52
53
  ...props
53
54
  }) {
@@ -62,7 +63,10 @@ const SideNavigation: React.FC<SGDS.Component.SideNavigation> = function ({
62
63
  return (
63
64
  <nav
64
65
  aria-label="Sections"
65
- className="ds_side-navigation"
66
+ className={[
67
+ 'ds_side-navigation',
68
+ className
69
+ ].join(' ')}
66
70
  data-module="ds-side-navigation"
67
71
  ref={ref}
68
72
  {...props}
@@ -61,3 +61,12 @@ test('passing additional props', () => {
61
61
  const nav = screen.getByRole('navigation');
62
62
  expect(nav.dataset.test).toEqual('foo');
63
63
  });
64
+
65
+ test('passing additional CSS classes', () => {
66
+ render(
67
+ <SiteNavigation className="foo" items={items}/>
68
+ );
69
+
70
+ const nav = screen.getByRole('navigation');
71
+ expect(nav).toHaveClass('foo', 'ds_site-navigation');
72
+ });
@@ -18,12 +18,16 @@ const SiteNavLink: React.FC<SGDS.Component.SiteNavigation.Link> = ({
18
18
  };
19
19
 
20
20
  const SiteNavigation: React.FC<SGDS.Component.SiteNavigation> = ({
21
+ className,
21
22
  items,
22
23
  ...props
23
24
  }) => {
24
25
  return (
25
26
  <nav
26
- className="ds_site-navigation"
27
+ className={[
28
+ 'ds_site-navigation',
29
+ className
30
+ ].join(' ')}
27
31
  {...props}
28
32
  >
29
33
  <ul className="ds_site-navigation__list">
@@ -151,3 +151,13 @@ test('passing additional props', () => {
151
151
  const searchFormContainer = searchForm.parentNode;
152
152
  expect(searchFormContainer?.dataset.test).toEqual('foo');
153
153
  });
154
+
155
+ test('passing additional CSS classes', () => {
156
+ render(
157
+ <SiteSearch className="foo" />
158
+ );
159
+
160
+ const searchForm = screen.getByRole('search');
161
+ const searchFormContainer = searchForm.parentNode;
162
+ expect(searchFormContainer).toHaveClass('foo', 'ds_site-search');
163
+ });
@@ -7,6 +7,7 @@ const SiteSearch: React.FC<SGDS.Component.SiteSearch> = function ({
7
7
  action = '/search',
8
8
  autocompleteEndpoint,
9
9
  autocompleteSuggestionMappingFunction,
10
+ className,
10
11
  id = 'site-search',
11
12
  method = 'GET',
12
13
  minLength = 3,
@@ -47,7 +48,8 @@ const SiteSearch: React.FC<SGDS.Component.SiteSearch> = function ({
47
48
  return (
48
49
  <div
49
50
  className={[
50
- 'ds_site-search',
51
+ 'ds_site-search', ,
52
+ className,
51
53
  hasAutocomplete ? 'ds_autocomplete' : undefined
52
54
  ].join(' ')}
53
55
  id={autocompleteId ? autocompleteId : undefined}
@@ -25,21 +25,21 @@ test('tag with custom colour', () => {
25
25
  expect(tag).toHaveClass('ds_tag--red');
26
26
  });
27
27
 
28
- test('tag with additional CSS class', () => {
28
+ test('passing additional props', () => {
29
29
  render(
30
- <Tag className="foo" title={tagText}/>
30
+ <Tag data-test="foo" title={tagText}/>
31
31
  );
32
32
 
33
33
  const tag = screen.getByText(tagText);
34
-
35
- expect(tag).toHaveClass('foo');
34
+ expect(tag?.dataset.test).toEqual('foo');
36
35
  });
37
36
 
38
- test('passing additional props', () => {
37
+ test('tag with additional CSS class', () => {
39
38
  render(
40
- <Tag data-test="foo" title={tagText}/>
39
+ <Tag className="foo" title={tagText}/>
41
40
  );
42
41
 
43
42
  const tag = screen.getByText(tagText);
44
- expect(tag?.dataset.test).toEqual('foo');
43
+
44
+ expect(tag).toHaveClass('foo', 'ds_tag');
45
45
  });
@@ -388,6 +388,19 @@ test('task list counts completed items from all groups for its status text and t
388
388
  expect(taskListStatusLink).toHaveAttribute('href', `#${tasks[0].id + '2'}`);
389
389
  });
390
390
 
391
+ test('passing additional props to task list', () => {
392
+ render(
393
+ <TaskList
394
+ title={taskListHeadingText}
395
+ data-test="foo"
396
+ />
397
+ );
398
+
399
+ const taskList = screen.getByRole('list');
400
+ const taskListWrapper = taskList.parentNode;
401
+ expect(taskListWrapper?.dataset.test).toEqual('foo');
402
+ });
403
+
391
404
  test('passing additional props to task group', () => {
392
405
  render(
393
406
  <TaskGroup data-test="foo">
@@ -407,3 +420,36 @@ test('passing additional props to task', () => {
407
420
  const task = document.querySelector('.ds_task-list__task');
408
421
  expect(task?.dataset.test).toEqual('foo');
409
422
  });
423
+
424
+ test('passing additional CSS classes to task list', () => {
425
+ render(
426
+ <TaskList
427
+ title={taskListHeadingText}
428
+ className="foo"
429
+ />
430
+ );
431
+
432
+ const taskList = screen.getByRole('list');
433
+ const taskListWrapper = taskList.parentNode;
434
+ expect(taskListWrapper).toHaveClass('foo');
435
+ });
436
+
437
+ test('passing additional CSS classes to task group', () => {
438
+ render(
439
+ <TaskGroup className="foo">
440
+ </TaskGroup>
441
+ );
442
+
443
+ const taskGroup = document.querySelector('.ds_task-list-group__section');
444
+ expect(taskGroup).toHaveClass('foo', 'ds_task-list-group__section');
445
+ });
446
+
447
+ test('passing additional CSS classes to task', () => {
448
+ render(
449
+ <Task className="foo">
450
+ </Task>
451
+ );
452
+
453
+ const task = document.querySelector('.ds_task-list__task');
454
+ expect(task).toHaveClass('foo', 'ds_task-list__task');
455
+ });
@@ -6,6 +6,7 @@ import Tag from '../tag/tag';
6
6
 
7
7
  export const Task: React.FC<SGDS.Component.TaskList.Task> = ({
8
8
  children,
9
+ className,
9
10
  href,
10
11
  id,
11
12
  isComplete = false,
@@ -20,7 +21,10 @@ export const Task: React.FC<SGDS.Component.TaskList.Task> = ({
20
21
 
21
22
  return (
22
23
  <li
23
- className="ds_task-list__task"
24
+ className={[
25
+ 'ds_task-list__task',
26
+ className
27
+ ].join(' ')}
24
28
  id={id}
25
29
  {...props}
26
30
  >
@@ -56,13 +60,17 @@ export const Task: React.FC<SGDS.Component.TaskList.Task> = ({
56
60
  */
57
61
  export const TaskGroup: React.FC<SGDS.Component.TaskList.Group> = ({
58
62
  children,
63
+ className,
59
64
  intro,
60
65
  title,
61
66
  ...props
62
67
  }) => {
63
68
  return (
64
69
  <li
65
- className="ds_task-list-group__section"
70
+ className={[
71
+ 'ds_task-list-group__section',
72
+ className
73
+ ].join(' ')}
66
74
  {...props}
67
75
  >
68
76
  <h2 className="ds_task-list-heading">{title}</h2>
@@ -76,8 +84,10 @@ export const TaskGroup: React.FC<SGDS.Component.TaskList.Group> = ({
76
84
 
77
85
  const TaskList: React.FC<SGDS.Component.TaskList> = ({
78
86
  children,
87
+ className,
79
88
  headingId = 'task-list',
80
- title
89
+ title,
90
+ ...props
81
91
  }) => {
82
92
  let taskCount = 0;
83
93
  let incompleteTaskIds: string[] = [];
@@ -112,7 +122,10 @@ const TaskList: React.FC<SGDS.Component.TaskList> = ({
112
122
  });
113
123
 
114
124
  return (
115
- <>
125
+ <div
126
+ className={className}
127
+ {...props}
128
+ >
116
129
  <h2 id={`${headingId}-status`} className="ds_task-list-status-heading">{title}</h2>
117
130
  <nav aria-labelledby={`${headingId}-status`} className="ds_task-list-status">
118
131
  <p>You have completed {completedTasksCount} of {taskCount} sections.</p>
@@ -121,7 +134,7 @@ const TaskList: React.FC<SGDS.Component.TaskList> = ({
121
134
  <ul className="ds_task-list">
122
135
  {children}
123
136
  </ul>
124
- </>
137
+ </div>
125
138
  );
126
139
  };
127
140