@scottish-government/designsystem-react 0.9.0-beta.0 → 0.10.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 (165) hide show
  1. package/.storybook/main.ts +20 -0
  2. package/.storybook/manager.ts +13 -0
  3. package/.storybook/preview-head.html +1 -0
  4. package/.storybook/preview.tsx +56 -0
  5. package/.storybook/sgdsArgTypes.ts +123 -0
  6. package/.storybook/sgdsTheme.ts +9 -0
  7. package/.storybook/vitest.setup.ts +7 -0
  8. package/@types/common/AbstractNotificationBanner.d.ts +2 -2
  9. package/@types/common/ActionLink.d.ts +1 -1
  10. package/@types/common/Icon.d.ts +1 -1
  11. package/@types/components/Accordion.d.ts +2 -2
  12. package/@types/components/Button.d.ts +5 -5
  13. package/@types/components/CategoryItem.d.ts +10 -0
  14. package/@types/components/CategoryList.d.ts +7 -0
  15. package/@types/components/Checkbox.d.ts +2 -2
  16. package/@types/components/ContentsNav.d.ts +1 -1
  17. package/@types/components/DatePicker.d.ts +1 -1
  18. package/@types/components/ErrorMessage.d.ts +1 -2
  19. package/@types/components/ErrorSummary.d.ts +1 -1
  20. package/@types/components/FileDownload.d.ts +2 -2
  21. package/@types/components/Metadata.d.ts +1 -1
  22. package/@types/components/Pagination.d.ts +1 -1
  23. package/@types/components/RadioButton.d.ts +2 -2
  24. package/@types/components/SideNavigation.d.ts +1 -1
  25. package/@types/components/SiteNavigation.d.ts +1 -1
  26. package/@types/components/SummaryList.d.ts +1 -1
  27. package/@types/components/Tabs.d.ts +3 -3
  28. package/@types/components/TextInput.d.ts +1 -1
  29. package/@types/sgds.d.ts +2 -1
  30. package/CHANGELOG.md +29 -0
  31. package/dist/common/AbstractNotificationBanner.jsx +4 -4
  32. package/dist/common/Icon.jsx +2 -2
  33. package/dist/components/Accordion/Accordion.jsx +3 -7
  34. package/dist/components/Button/Button.jsx +6 -6
  35. package/dist/components/CategoryItem/CategoryItem.jsx +35 -0
  36. package/dist/components/CategoryList/CategoryList.jsx +55 -0
  37. package/dist/components/Checkbox/Checkbox.jsx +5 -5
  38. package/dist/components/Checkbox/CheckboxGroup.jsx +2 -2
  39. package/dist/components/ContentsNav/ContentsNav.jsx +2 -2
  40. package/dist/components/DatePicker/DatePicker.jsx +1 -1
  41. package/dist/components/ErrorMessage/ErrorMessage.jsx +3 -3
  42. package/dist/components/FileDownload/FileDownload.jsx +2 -2
  43. package/dist/components/NotificationBanner/NotificationBanner.jsx +2 -2
  44. package/dist/components/PageMetadata/PageMetadata.jsx +4 -4
  45. package/dist/components/Pagination/Pagination.jsx +4 -4
  46. package/dist/components/Question/Question.jsx +1 -1
  47. package/dist/components/RadioButton/RadioButton.jsx +3 -3
  48. package/dist/components/RadioButton/RadioGroup.jsx +3 -3
  49. package/dist/components/Select/Select.jsx +1 -1
  50. package/dist/components/SideNavigation/SideNavigation.jsx +2 -2
  51. package/dist/components/SiteHeader/SiteHeader.jsx +3 -3
  52. package/dist/components/SiteNavigation/SiteNavigation.jsx +2 -2
  53. package/dist/components/SiteSearch/SiteSearch.jsx +1 -1
  54. package/dist/components/SkipLinks/SkipLinks.jsx +1 -1
  55. package/dist/components/SummaryList/SummaryList.jsx +3 -3
  56. package/dist/components/Tabs/Tabs.jsx +6 -7
  57. package/dist/components/TextInput/TextInput.jsx +5 -5
  58. package/dist/components/Textarea/Textarea.jsx +1 -1
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/dist/utils/context.js +1 -1
  61. package/package.json +14 -3
  62. package/src/common/AbstractNotificationBanner.test.tsx +1 -1
  63. package/src/common/AbstractNotificationBanner.tsx +4 -4
  64. package/src/common/Icon.test.tsx +1 -1
  65. package/src/common/Icon.tsx +2 -2
  66. package/src/components/Accordion/Accordion.stories.tsx +111 -0
  67. package/src/components/Accordion/Accordion.test.tsx +5 -30
  68. package/src/components/Accordion/Accordion.tsx +4 -9
  69. package/src/components/AspectBox/AspectBox.stories.tsx +64 -0
  70. package/src/components/BackToTop/BackToTop.stories.tsx +36 -0
  71. package/src/components/Breadcrumbs/Breadcrumbs.stories.tsx +49 -0
  72. package/src/components/Breadcrumbs/Breadcrumbs.tsx +1 -1
  73. package/src/components/Button/Button.stories.tsx +194 -0
  74. package/src/components/Button/Button.test.tsx +4 -4
  75. package/src/components/Button/Button.tsx +9 -9
  76. package/src/components/CategoryItem/CategoryItem.stories.tsx +55 -0
  77. package/src/components/CategoryItem/CategoryItem.test.tsx +93 -0
  78. package/src/components/CategoryItem/CategoryItem.tsx +56 -0
  79. package/src/components/CategoryList/CategoryList.stories.tsx +65 -0
  80. package/src/components/CategoryList/CategoryList.test.tsx +59 -0
  81. package/src/components/CategoryList/CategoryList.tsx +33 -0
  82. package/src/components/Checkbox/Checkbox.stories.tsx +85 -0
  83. package/src/components/Checkbox/Checkbox.test.tsx +2 -2
  84. package/src/components/Checkbox/Checkbox.tsx +7 -7
  85. package/src/components/Checkbox/CheckboxGroup.stories.tsx +68 -0
  86. package/src/components/Checkbox/CheckboxGroup.tsx +2 -2
  87. package/src/components/ConfirmationMessage/ConfirmationMessage.stories.tsx +38 -0
  88. package/src/components/ContentsNav/ContentsNav.stories.tsx +43 -0
  89. package/src/components/ContentsNav/ContentsNav.test.tsx +2 -2
  90. package/src/components/ContentsNav/ContentsNav.tsx +2 -2
  91. package/src/components/CookieBanner/CookieBanner.stories.tsx +33 -0
  92. package/src/components/DatePicker/DatePicker.stories.tsx +113 -0
  93. package/src/components/DatePicker/DatePicker.tsx +1 -1
  94. package/src/components/Details/Details.stories.tsx +36 -0
  95. package/src/components/ErrorMessage/ErrorMessage.stories.tsx +19 -0
  96. package/src/components/ErrorMessage/ErrorMessage.test.tsx +3 -15
  97. package/src/components/ErrorMessage/ErrorMessage.tsx +1 -3
  98. package/src/components/ErrorSummary/ErrorSummary.stories.tsx +38 -0
  99. package/src/components/FileDownload/FileDownload.stories.tsx +75 -0
  100. package/src/components/FileDownload/FileDownload.test.tsx +1 -1
  101. package/src/components/FileDownload/FileDownload.tsx +2 -2
  102. package/src/components/HideThisPage/HideThisPage.stories.tsx +20 -0
  103. package/src/components/InsetText/InsetText.stories.tsx +21 -0
  104. package/src/components/NotificationBanner/NotificationBanner.stories.tsx +57 -0
  105. package/src/components/NotificationBanner/NotificationBanner.test.tsx +1 -1
  106. package/src/components/NotificationBanner/NotificationBanner.tsx +4 -4
  107. package/src/components/NotificationPanel/NotificationPanel.stories.tsx +32 -0
  108. package/src/components/PageHeader/PageHeader.stories.tsx +60 -0
  109. package/src/components/PageMetadata/PageMetadata.stories.tsx +58 -0
  110. package/src/components/PageMetadata/PageMetadata.test.tsx +2 -2
  111. package/src/components/PageMetadata/PageMetadata.tsx +4 -4
  112. package/src/components/Pagination/Pagination.stories.tsx +69 -0
  113. package/src/components/Pagination/Pagination.test.tsx +1 -1
  114. package/src/components/Pagination/Pagination.tsx +4 -4
  115. package/src/components/PhaseBanner/PhaseBanner.stories.tsx +38 -0
  116. package/src/components/Question/Question.stories.tsx +78 -0
  117. package/src/components/Question/Question.tsx +1 -1
  118. package/src/components/RadioButton/RadioButton.stories.tsx +67 -0
  119. package/src/components/RadioButton/RadioButton.test.tsx +2 -1
  120. package/src/components/RadioButton/RadioButton.tsx +4 -4
  121. package/src/components/RadioButton/RadioGroup.stories.tsx +77 -0
  122. package/src/components/RadioButton/RadioGroup.test.tsx +2 -2
  123. package/src/components/RadioButton/RadioGroup.tsx +4 -4
  124. package/src/components/Select/Select.stories.tsx +76 -0
  125. package/src/components/Select/Select.tsx +1 -1
  126. package/src/components/SequentialNavigation/SequentialNavigation.stories.tsx +31 -0
  127. package/src/components/SideNavigation/SideNavigation.stories.tsx +92 -0
  128. package/src/components/SideNavigation/SideNavigation.test.tsx +2 -2
  129. package/src/components/SideNavigation/SideNavigation.tsx +2 -2
  130. package/src/components/SiteFooter/SiteFooter.stories.tsx +65 -0
  131. package/src/components/SiteHeader/SiteHeader.stories.tsx +92 -0
  132. package/src/components/SiteHeader/SiteHeader.tsx +2 -7
  133. package/src/components/SiteNavigation/SiteNavigation.stories.tsx +45 -0
  134. package/src/components/SiteNavigation/SiteNavigation.test.tsx +1 -1
  135. package/src/components/SiteNavigation/SiteNavigation.tsx +2 -2
  136. package/src/components/SiteSearch/SiteSearch.stories.tsx +81 -0
  137. package/src/components/SiteSearch/SiteSearch.tsx +1 -1
  138. package/src/components/SkipLinks/SkipLinks.stories.tsx +57 -0
  139. package/src/components/SkipLinks/SkipLinks.tsx +1 -1
  140. package/src/components/SummaryCard/SummaryCard.stories.tsx +46 -0
  141. package/src/components/SummaryList/SummaryList.stories.tsx +75 -0
  142. package/src/components/SummaryList/SummaryList.test.tsx +1 -1
  143. package/src/components/SummaryList/SummaryList.tsx +3 -3
  144. package/src/components/Table/Table.stories.tsx +96 -0
  145. package/src/components/Tabs/Tabs.stories.tsx +90 -0
  146. package/src/components/Tabs/Tabs.test.tsx +6 -8
  147. package/src/components/Tabs/Tabs.tsx +8 -9
  148. package/src/components/Tag/Tag.stories.tsx +25 -0
  149. package/src/components/TaskList/TaskList.stories.tsx +129 -0
  150. package/src/components/TextInput/TextInput.stories.tsx +123 -0
  151. package/src/components/TextInput/TextInput.test.tsx +2 -2
  152. package/src/components/TextInput/TextInput.tsx +5 -5
  153. package/src/components/Textarea/Textarea.stories.tsx +71 -0
  154. package/src/components/Textarea/Textarea.tsx +1 -1
  155. package/src/components/WarningText/WarningText.stories.tsx +21 -0
  156. package/src/utils/context.ts +1 -1
  157. package/static/data/autocomplete-dummy-data.json +2361 -0
  158. package/static/images/highland-cow.jpg +0 -0
  159. package/static/images/scottish-government--min.svg +11 -0
  160. package/static/images/scottish-government.svg +6 -0
  161. package/tsconfig.json +2 -1
  162. package/vite.config.ts +45 -11
  163. package/vitest-setup.ts +1 -0
  164. package/vitest.shims.d.ts +1 -0
  165. package/src/utils/slugify.ts +0 -13
@@ -0,0 +1,65 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import CategoryList from './CategoryList';
5
+ import CategoryItem from '../CategoryItem/CategoryItem';
6
+
7
+ const meta = {
8
+ title: 'Components/Category list',
9
+ component: CategoryList,
10
+ argTypes: {
11
+ children: argTypes.children(),
12
+ isGrid: {
13
+ description: 'Show the category items in a grid',
14
+ type: 'boolean'
15
+ },
16
+ isOrdered: {
17
+ description: 'Use an ordered list for the category items in the list',
18
+ type: 'boolean'
19
+ }
20
+ },
21
+ args: {
22
+ }
23
+ } satisfies Meta<typeof CategoryList>;
24
+
25
+ export default meta;
26
+ type Story = StoryObj<typeof meta>;
27
+
28
+ export const Default: Story = {
29
+ render: (args) => (
30
+ <CategoryList {...args}>
31
+ <CategoryItem title="Public transport, bus passes and discounts" href="#foo">Find information about local travel by road, rail and water and National Entitlement Cards.</CategoryItem>
32
+ <CategoryItem title="Parking and Blue Badges" href="#bar">Find out about getting a disabled parking space and information on Blue Badges.</CategoryItem>
33
+ <CategoryItem title="Apply to reduce your driving disqualification period" href="#baz">How to apply to court to reduce your driving ban. Includes who can apply and how much it costs.</CategoryItem>
34
+ <CategoryItem title="Road safety: parking tickets, fines and bans" href="#qux">Find out about the drink-drive limit, how to stay safe on the roads and what to do if you receive parking tickets.</CategoryItem>
35
+ </CategoryList>
36
+ )
37
+ };
38
+
39
+ export const Grid: Story = {
40
+ args: {
41
+ isGrid: true
42
+ },
43
+ render: (args) => (
44
+ <CategoryList {...args}>
45
+ <CategoryItem title="Public transport, bus passes and discounts" href="#foo">Find information about local travel by road, rail and water and National Entitlement Cards.</CategoryItem>
46
+ <CategoryItem title="Parking and Blue Badges" href="#bar">Find out about getting a disabled parking space and information on Blue Badges.</CategoryItem>
47
+ <CategoryItem title="Apply to reduce your driving disqualification period" href="#baz">How to apply to court to reduce your driving ban. Includes who can apply and how much it costs.</CategoryItem>
48
+ <CategoryItem title="Road safety: parking tickets, fines and bans" href="#qux">Find out about the drink-drive limit, how to stay safe on the roads and what to do if you receive parking tickets.</CategoryItem>
49
+ </CategoryList>
50
+ )
51
+ };
52
+
53
+ export const OrderedList: Story = {
54
+ args: {
55
+ isOrdered: true
56
+ },
57
+ render: (args) => (
58
+ <CategoryList {...args}>
59
+ <CategoryItem title="Public transport, bus passes and discounts" href="#foo">Find information about local travel by road, rail and water and National Entitlement Cards.</CategoryItem>
60
+ <CategoryItem title="Parking and Blue Badges" href="#bar">Find out about getting a disabled parking space and information on Blue Badges.</CategoryItem>
61
+ <CategoryItem title="Apply to reduce your driving disqualification period" href="#baz">How to apply to court to reduce your driving ban. Includes who can apply and how much it costs.</CategoryItem>
62
+ <CategoryItem title="Road safety: parking tickets, fines and bans" href="#qux">Find out about the drink-drive limit, how to stay safe on the roads and what to do if you receive parking tickets.</CategoryItem>
63
+ </CategoryList>
64
+ )
65
+ };
@@ -0,0 +1,59 @@
1
+ import { test, expect } from 'vitest';
2
+ import { render, screen, within } from '@testing-library/react';
3
+ import CategoryList from './CategoryList';
4
+ import CategoryItem from '../CategoryItem/CategoryItem';
5
+
6
+ test('category list renders correctly', () => {
7
+ render(
8
+ <CategoryList>
9
+ <CategoryItem data-testid="category-item" title="Public transport, bus passes and discounts" href="#foo">Find information about local travel by road, rail and water and National Entitlement Cards.</CategoryItem>
10
+ <CategoryItem title="Parking and Blue Badges" href="#bar">Find out about getting a disabled parking space and information on Blue Badges.</CategoryItem>
11
+ <CategoryItem title="Apply to reduce your driving disqualification period" href="#baz">How to apply to court to reduce your driving ban. Includes who can apply and how much it costs.</CategoryItem>
12
+ <CategoryItem title="Road safety: parking tickets, fines and bans" href="#qux">Find out about the drink-drive limit, how to stay safe on the roads and what to do if you receive parking tickets.</CategoryItem>
13
+ </CategoryList>
14
+ );
15
+
16
+ const categoryList = screen.getByRole('list');
17
+ expect(categoryList).toHaveClass('ds_category-list');
18
+ expect(categoryList).not.toHaveClass('ds_category-list--grid');
19
+ expect(categoryList.tagName).toEqual('UL');
20
+
21
+ const child = within(categoryList).getByTestId('category-item');
22
+ expect(child.tagName).toEqual('LI');
23
+ });
24
+
25
+ test('ordered category list', () => {
26
+ render(
27
+ <CategoryList isOrdered data-test="foo" />
28
+ );
29
+
30
+ const categoryList = screen.getByRole('list');
31
+ expect(categoryList.tagName).toEqual('OL');
32
+ });
33
+
34
+ test('grid category list', () => {
35
+ render(
36
+ <CategoryList isGrid data-test="foo" />
37
+ );
38
+
39
+ const categoryList = screen.getByRole('list');
40
+ expect(categoryList).toHaveClass('ds_category-list--grid');
41
+ });
42
+
43
+ test('passing additional props', () => {
44
+ render(
45
+ <CategoryList data-test="foo" />
46
+ );
47
+
48
+ const categoryList = screen.getByRole('list');
49
+ expect(categoryList.dataset.test).toEqual('foo');
50
+ });
51
+
52
+ test('passing additional CSS classes', () => {
53
+ render(
54
+ <CategoryList className="foo" />
55
+ );
56
+
57
+ const categoryList = screen.getByRole('list');
58
+ expect(categoryList).toHaveClass('foo');
59
+ });
@@ -0,0 +1,33 @@
1
+ import React, { Children } from 'react';
2
+ import WrapperTag from "../../common/WrapperTag";
3
+
4
+ const CategoryList = ({
5
+ children,
6
+ className,
7
+ isGrid,
8
+ isOrdered,
9
+ ...props
10
+ }: SGDS.Component.CategoryList) => {
11
+ function processChild(child: React.ReactNode) {
12
+ const thisChild = child as React.ReactElement<SGDS.Component.CategoryItem>
13
+ return React.cloneElement(thisChild, {tagName: 'li'})
14
+ }
15
+
16
+ return (
17
+ <WrapperTag
18
+ tagName={isOrdered ? 'ol' : 'ul'}
19
+ className={[
20
+ 'ds_category-list',
21
+ isGrid && 'ds_category-list--grid',
22
+ className
23
+ ].join(' ')}
24
+ {...props}
25
+ >
26
+ {Children.map(children, child => processChild(child))}
27
+ </WrapperTag>
28
+ );
29
+ };
30
+
31
+ CategoryList.displayName = 'CategoryList';
32
+
33
+ export default CategoryList;
@@ -0,0 +1,85 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import Checkbox from './Checkbox';
5
+
6
+ const meta = {
7
+ title: 'Components/Checkbox',
8
+ component: Checkbox,
9
+ argTypes: {
10
+ checked: {
11
+ control: 'boolean',
12
+ description: 'The checkbox is checked on load'
13
+ },
14
+ hintText: argTypes.hintText,
15
+ exclusive: {
16
+ control: 'boolean',
17
+ description: 'Whether the checkbox is exclusive (e.g. a \'none\' option)'
18
+ },
19
+ id: argTypes.id(),
20
+ label: argTypes.label(),
21
+ name: {
22
+ type: 'string'
23
+ },
24
+ onBlur: argTypes.onBlur(),
25
+ onChange: argTypes.onChange(),
26
+ small: argTypes.isSmall()
27
+ },
28
+ args: {
29
+ label: 'Benefits and grants',
30
+ id: 'benefits-and-grants'
31
+ }
32
+ } satisfies Meta<typeof Checkbox>;
33
+
34
+ export default meta;
35
+ type Story = StoryObj<typeof meta>;
36
+
37
+ export const Default: Story = {
38
+ };
39
+
40
+ export const CheckedByDefault: Story = {
41
+ args: {
42
+ checked: true,
43
+ id: 'checked'
44
+ }
45
+ };
46
+
47
+ export const SmallCheckbox: Story = {
48
+ args: {
49
+ isSmall: true,
50
+ id: 'small'
51
+ }
52
+ };
53
+
54
+ export const HintText: Story = {
55
+ args: {
56
+ hintText: 'Information on benefits, funds and grants, including Child Benefit and tax credits.',
57
+ id: 'hinttext'
58
+ }
59
+ };
60
+
61
+ export const CustomNameAttribute: Story = {
62
+ args: {
63
+ name: 'myName',
64
+ id: 'nameattribute'
65
+ }
66
+ };
67
+
68
+ export const Blur: Story = {
69
+ args: {
70
+ onBlur: () => {console.log('checkbox blur')}
71
+ },
72
+ play: async ({ canvas, userEvent }) => {
73
+ await userEvent.click(canvas.getByRole('checkbox'));
74
+ await userEvent.tab();
75
+ }
76
+ }
77
+
78
+ export const Change: Story = {
79
+ args: {
80
+ onChange: () => {console.log('checkbox change')}
81
+ },
82
+ play: async ({ canvas, userEvent }) => {
83
+ await userEvent.click(canvas.getByRole('checkbox'));
84
+ }
85
+ }
@@ -34,7 +34,7 @@ test('checked checkbox', () => {
34
34
 
35
35
  test('exclusive checkbox', () => {
36
36
  render(
37
- <Checkbox exclusive label="Pension Credit" id="pensioncredit" />
37
+ <Checkbox isExclusive label="Pension Credit" id="pensioncredit" />
38
38
  );
39
39
 
40
40
  const checkbox = screen.getByRole('checkbox');
@@ -88,7 +88,7 @@ test('checkbox with hint text', () => {
88
88
 
89
89
  test('small checkbox', () => {
90
90
  render(
91
- <Checkbox small label="Pension Credit" id="pensioncredit" />
91
+ <Checkbox isSmall label="Pension Credit" id="pensioncredit" />
92
92
  );
93
93
 
94
94
  const checkbox = screen.getByRole('checkbox');
@@ -7,15 +7,15 @@ const Checkbox = ({
7
7
  checked,
8
8
  hintText,
9
9
  id,
10
- exclusive,
10
+ isSmall,
11
+ isExclusive,
11
12
  label,
12
13
  name,
13
14
  onBlur,
14
- onChange,
15
- small
15
+ onChange
16
16
  }: SGDS.Component.Checkbox) => {
17
17
  const hintTextId = `hint-text-${id}`;
18
- const behaviour = exclusive && 'exclusive';
18
+ const behaviour = isExclusive && 'exclusive';
19
19
 
20
20
  function handleBlur(event: React.FocusEvent) {
21
21
  if (typeof onBlur === 'function') {
@@ -29,15 +29,15 @@ const Checkbox = ({
29
29
  }
30
30
  }
31
31
 
32
- small = small || useContext(CheckboxRadioContext).small;
32
+ isSmall = isSmall || useContext(CheckboxRadioContext).isSmall;
33
33
 
34
34
  return (
35
35
  <>
36
- {exclusive && <p className="ds_checkbox-separator">or</p>}
36
+ {isExclusive && <p className="ds_checkbox-separator">or</p>}
37
37
  <div
38
38
  className={[
39
39
  'ds_checkbox',
40
- small && 'ds_checkbox--small'
40
+ isSmall && 'ds_checkbox--small'
41
41
  ].join(' ')}>
42
42
 
43
43
  <input
@@ -0,0 +1,68 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import CheckboxGroup from './CheckboxGroup';
5
+ import Checkbox from './Checkbox';
6
+
7
+ const meta = {
8
+ component: CheckboxGroup,
9
+ title: 'Components/CheckboxGroup',
10
+ argTypes: {
11
+ children: argTypes.children(),
12
+ isSmall: argTypes.isSmall()
13
+ },
14
+ args: {
15
+ children: <>
16
+ <Checkbox
17
+ checked
18
+ id="universal-credit"
19
+ label="Universal Credit"
20
+ />
21
+ <Checkbox
22
+ id="pension-credit"
23
+ label="Pension Credit"
24
+ />
25
+ <Checkbox
26
+ id="jsa"
27
+ label="Income-based Job Seeker's Allowance"
28
+ />
29
+ </>
30
+ }
31
+ } satisfies Meta<typeof CheckboxGroup>;
32
+
33
+ export default meta;
34
+ type Story = StoryObj<typeof meta>;
35
+
36
+ export const Default: Story = {
37
+ };
38
+
39
+ export const SmallCheckboxes: Story = {
40
+ args: {
41
+ isSmall: true
42
+ }
43
+ };
44
+
45
+ export const ExclusiveCheckbox: Story = {
46
+ args: {
47
+ children: <>
48
+ <Checkbox
49
+ checked
50
+ id="universal-creditx"
51
+ label="Universal Credit"
52
+ />
53
+ <Checkbox
54
+ id="pension-creditx"
55
+ label="Pension Credit"
56
+ />
57
+ <Checkbox
58
+ id="jsax"
59
+ label="Income-based Job Seeker's Allowance"
60
+ />
61
+ <Checkbox
62
+ isExclusive
63
+ id="nonex"
64
+ label="No, I do not receive any of these benefits"
65
+ />
66
+ </>
67
+ }
68
+ }
@@ -7,7 +7,7 @@ import DSCheckboxes from '@scottish-government/design-system/src/forms/checkbox/
7
7
  export const CheckboxGroup = ({
8
8
  children,
9
9
  className,
10
- small = false,
10
+ isSmall,
11
11
  ...props
12
12
  }: SGDS.Component.Checkbox.Group) => {
13
13
  const ref = useRef(null);
@@ -29,7 +29,7 @@ export const CheckboxGroup = ({
29
29
  ref={ref}
30
30
  {...props}
31
31
  >
32
- <CheckboxRadioContext value={{small, name: ''}}>
32
+ <CheckboxRadioContext value={{isSmall: !!isSmall, name: ''}}>
33
33
  {children}
34
34
  </CheckboxRadioContext>
35
35
  </div>
@@ -0,0 +1,38 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import ConfirmationMessage from './ConfirmationMessage';
5
+
6
+ const meta = {
7
+ title: 'Components/Confirmation Message',
8
+ component: ConfirmationMessage,
9
+ argTypes: {
10
+ headingLevel: argTypes.headingLevel(),
11
+ ariaLive: argTypes.ariaLive(),
12
+ children: argTypes.children()
13
+ },
14
+ args: {
15
+ ariaLive: 'polite',
16
+ children: (<p>You have added the landlord <strong>John Smith</strong> to the application.</p>),
17
+ headingLevel: 'h3',
18
+ title: 'Landlord added successfully',
19
+ }
20
+ } satisfies Meta<typeof ConfirmationMessage>;
21
+
22
+ export default meta;
23
+ type Story = StoryObj<typeof meta>;
24
+
25
+ export const Default: Story = {
26
+ };
27
+
28
+ export const NoChildren: Story = {
29
+ args: {
30
+ children: undefined
31
+ }
32
+ };
33
+
34
+ export const DifferentHeadingLevel: Story = {
35
+ args: {
36
+ headingLevel: 'h2'
37
+ }
38
+ };
@@ -0,0 +1,43 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import ContentsNav from './ContentsNav';
5
+
6
+ const meta = {
7
+ title: 'Components/Contents nav',
8
+ component: ContentsNav,
9
+ argTypes: {
10
+ ariaLabel: argTypes.ariaLabel({description: 'Text to use for the content nav\'s aria-label property'}),
11
+ children: argTypes.children(),
12
+ linkComponent: argTypes.linkComponent(),
13
+ title: {
14
+ description: 'Title of the contents nav',
15
+ type: 'string'
16
+ }
17
+ },
18
+ args: {
19
+ children: <>
20
+ <ContentsNav.Item current>
21
+ Apply for Blue Badge
22
+ </ContentsNav.Item>
23
+ <ContentsNav.Item href="#2">
24
+ Eligibility
25
+ </ContentsNav.Item>
26
+ <ContentsNav.Item href="#3">
27
+ Using your Blue Badge
28
+ </ContentsNav.Item>
29
+ <ContentsNav.Item href="#4">
30
+ Report a lost, stolen or misuesd Blue Badge
31
+ </ContentsNav.Item>
32
+ <ContentsNav.Item href="#5">
33
+ Changing or handing back a Blue Badge
34
+ </ContentsNav.Item>
35
+ </>
36
+ }
37
+ } satisfies Meta<typeof ContentsNav>;
38
+
39
+ export default meta;
40
+ type Story = StoryObj<typeof meta>;
41
+
42
+ export const Default: Story = {
43
+ };
@@ -72,7 +72,7 @@ test('contents nav item without href', () => {
72
72
 
73
73
  test('current contents nav item with href', () => {
74
74
  render(
75
- <ContentsNav.Item current href={ITEM_HREF}>{ITEM_TITLE}</ContentsNav.Item>
75
+ <ContentsNav.Item isCurrent href={ITEM_HREF}>{ITEM_TITLE}</ContentsNav.Item>
76
76
  );
77
77
 
78
78
  const listItem = screen.getByRole('listitem');
@@ -84,7 +84,7 @@ test('current contents nav item with href', () => {
84
84
 
85
85
  test('current contents nav item without href', () => {
86
86
  render(
87
- <ContentsNav.Item current>{ITEM_TITLE}</ContentsNav.Item>
87
+ <ContentsNav.Item isCurrent>{ITEM_TITLE}</ContentsNav.Item>
88
88
  );
89
89
 
90
90
  const listItem = screen.getByRole('listitem');
@@ -2,14 +2,14 @@ import React from 'react';
2
2
 
3
3
  const ContentsNavItem = ({
4
4
  children,
5
- current,
5
+ isCurrent,
6
6
  href,
7
7
  linkComponent
8
8
  }: SGDS.Component.ContentsNav.ContentsNavItem) => {
9
9
  const classNames = ['ds_contents-nav__link'];
10
10
  let ariaCurrent: React.AriaAttributes["aria-current"];
11
11
 
12
- if (current) {
12
+ if (isCurrent) {
13
13
  classNames.push('ds_current');
14
14
  ariaCurrent = 'page';
15
15
  }
@@ -0,0 +1,33 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import CookieBanner from './CookieBanner';
5
+ import Button from '../Button/Button';
6
+
7
+ const meta = {
8
+ title: 'Components/Cookie banner',
9
+ component: CookieBanner,
10
+ argTypes: {
11
+ children: argTypes.children()
12
+ },
13
+ args: {
14
+ children: [
15
+ <p key="foo">We use <a href="/cookies/">cookies</a> to collect anonymous data to help us improve your site browsing
16
+ experience.</p>,
17
+ <p key="bar">Click 'Accept all cookies' to agree to all cookies that collect anonymous data.
18
+ To only allow the cookies that make the site work, click 'Use essential cookies only.' Visit 'Set cookie preferences' to control specific cookies.</p>,
19
+ <CookieBanner.Buttons key="baz">
20
+ <Button className="js-accept-all-cookies" small buttonStyle="secondary">Accept all cookies</Button>
21
+ <Button className="js-accept-essential-cookies" small buttonStyle="secondary">Use essential cookies only</Button>
22
+ <a href="/cookies/">Set cookie preferences</a>
23
+ </CookieBanner.Buttons>
24
+ ]
25
+ }
26
+ } satisfies Meta<typeof CookieBanner>;
27
+
28
+ export default meta;
29
+ type Story = StoryObj<typeof meta>;
30
+
31
+ export const Default: Story = {
32
+
33
+ };
@@ -0,0 +1,113 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import DatePicker from './DatePicker';
5
+
6
+ const meta = {
7
+ title: 'Components/Date picker',
8
+ component: DatePicker,
9
+ argTypes: {
10
+ dateSelectCallback: {},
11
+ disabledDates: {
12
+ control: { type: 'text' },
13
+ description: 'Space-separated list of dates to disable in the date picker'
14
+ },
15
+ hasError: argTypes.hasError(),
16
+ errorMessage: argTypes.errorMessage(),
17
+ hintText: argTypes.hintText(),
18
+ id: argTypes.id(),
19
+ label: argTypes.label(),
20
+ maxDate: {
21
+ control: { type: 'text' },
22
+ description: 'Latest selectable date in the date picker'
23
+ },
24
+ minDate: {
25
+ control: { type: 'text' },
26
+ description: 'Earliest selectable date in the date picker'
27
+ },
28
+ multiple: {
29
+ control: 'boolean',
30
+ description: 'Whether to display the day, month and year as separate fields'
31
+ },
32
+ name: {
33
+ control: { type: 'text' }
34
+ },
35
+ onBlur: argTypes.onBlur(),
36
+ onChange: argTypes.onChange(),
37
+ value: {
38
+ control: { type: 'text' }
39
+ },
40
+ width: argTypes.inputWidth()
41
+ },
42
+ args: {
43
+ label: 'Date of birth',
44
+ id: 'date-of-birth'
45
+ }
46
+ } satisfies Meta<typeof DatePicker>;
47
+
48
+ export default meta;
49
+ type Story = StoryObj<typeof meta>;
50
+
51
+ export const Default: Story = {
52
+ };
53
+
54
+ export const InitialValue: Story = {
55
+ args: {
56
+ value: '01/12/2020'
57
+ }
58
+ };
59
+
60
+ export const HintText: Story = {
61
+ args: {
62
+ hintText: 'Use \'dd/mm/yyyy\' format.'
63
+ }
64
+ };
65
+
66
+ export const Error: Story = {
67
+ args: {
68
+ hasError: true,
69
+ errorMessage: 'Please enter a valid date.'
70
+ }
71
+ };
72
+
73
+ export const Multiple: Story = {
74
+ args: {
75
+ multiple: true
76
+ }
77
+ };
78
+
79
+ export const MultipleInitialValue: Story = {
80
+ args: {
81
+ multiple: true,
82
+ value: '01/12/2020'
83
+ }
84
+ };
85
+
86
+ export const DateRestrictions: Story = {
87
+ args: {
88
+ disabledDates: '12/07/2025 13/07/2025 19/07/2025 20/07/2025',
89
+ maxDate: '25/07/2025',
90
+ minDate: '07/07/2025'
91
+ }
92
+ };
93
+
94
+ export const Blur: Story = {
95
+ args: {
96
+ onBlur: () => {console.log('date picker blur')}
97
+ },
98
+ play: async ({ canvas, userEvent }) => {
99
+ await userEvent.click(canvas.getByRole('textbox'));
100
+ await userEvent.tab();
101
+ }
102
+ }
103
+
104
+ export const Change: Story = {
105
+ args: {
106
+ onChange: () => {console.log('date picker change')}
107
+ },
108
+ play: async ({ canvas, userEvent }) => {
109
+ await userEvent.click(canvas.getByRole('textbox'));
110
+ await userEvent.type(canvas.getByRole('textbox'),'01/12/2020');
111
+ await userEvent.tab();
112
+ }
113
+ }
@@ -64,7 +64,7 @@ const DatePicker = ({
64
64
  {(multiple ? (
65
65
  <fieldset className="ds_datepicker__input-wrapper">
66
66
  <legend>{label}</legend>
67
- {errorMessage && <ErrorMessage text={errorMessage}/>}
67
+ {errorMessage && <ErrorMessage>{errorMessage}</ErrorMessage>}
68
68
  <div>
69
69
  <TextInput
70
70
  className="js-datepicker-date"