@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,96 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+
3
+ import Table from './Table';
4
+
5
+ const meta = {
6
+ title: 'Components/Table',
7
+ component: Table,
8
+ argTypes: {
9
+ smallscreen: {
10
+ description: 'The behaviour to use on small screens',
11
+ children: { control: false },
12
+ control: { type: 'select' },
13
+ options: [undefined,'boxes', 'scrolling'],
14
+ type: 'string',
15
+ }
16
+ },
17
+ args: {
18
+ children: <>
19
+ <caption>Public holidays in 2020</caption>
20
+ <thead>
21
+ <tr>
22
+ <th scope="col">
23
+ Date
24
+ </th>
25
+ <th scope="col">
26
+ Day
27
+ </th>
28
+ <th scope="col">
29
+ Holiday
30
+ </th>
31
+ </tr>
32
+ </thead>
33
+ <tbody>
34
+ <tr>
35
+ <td>
36
+ 10 April
37
+ </td>
38
+ <td>
39
+ Friday
40
+ </td>
41
+ <td>
42
+ Good Friday
43
+ </td>
44
+ </tr>
45
+ <tr>
46
+ <td>
47
+ 8 May
48
+ </td>
49
+ <td>
50
+ Friday
51
+ </td>
52
+ <td>
53
+ Early May Bank Holiday
54
+ </td>
55
+ </tr>
56
+ <tr>
57
+ <td>
58
+ 25 May
59
+ </td>
60
+ <td>
61
+ Monday
62
+ </td>
63
+ <td>
64
+ Spring Bank Holiday
65
+ </td>
66
+ </tr>
67
+ <tr>
68
+ <td>
69
+ 3 August
70
+ </td>
71
+ <td>
72
+ Monday
73
+ </td>
74
+ <td>
75
+ Summer Bank Holiday
76
+ </td>
77
+ </tr>
78
+ </tbody>
79
+ </>
80
+ }
81
+ } satisfies Meta<typeof Table>;
82
+
83
+ export default meta;
84
+ type Story = StoryObj<typeof meta>;
85
+
86
+ export const Default: Story = {
87
+
88
+ };
89
+
90
+ export const Boxes: Story = {
91
+ args: {smallscreen: 'boxes'}
92
+ };
93
+
94
+ export const Scrolling: Story = {
95
+ args: {smallscreen: 'scrolling'}
96
+ };
@@ -0,0 +1,90 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import Tabs from './Tabs';
5
+
6
+ const meta = {
7
+ title: 'Components/Tabs',
8
+ component: Tabs,
9
+ argTypes: {
10
+ baseId: {
11
+ description: 'A string that IDs for subcomponents are derived from.',
12
+ type: {
13
+ name: 'string',
14
+ required: true
15
+ }
16
+ },
17
+ headingLevel: argTypes.headingLevel({
18
+ description: 'Heading level to use for the tab container\'s title',
19
+ }),
20
+ isBorderless: {
21
+ description: 'Whether to give each tab a border',
22
+ control: 'boolean'
23
+ },
24
+ isManual: {
25
+ control: 'boolean',
26
+ description: 'Whether to require manual tab activation',
27
+ type: 'boolean'
28
+ },
29
+ title: {
30
+ description: 'The title of the tab list',
31
+ type: 'string'
32
+ },
33
+ children: argTypes.children()
34
+ },
35
+ args: {
36
+ baseId: 'my-tabs',
37
+ children: [
38
+ <Tabs.Item key="foo" tabLabel="Courses and funding">
39
+ <h3>Search for training courses and funding</h3>
40
+ <p>A wide range of training courses for your employees are available.</p>
41
+ <p>Opportunities include distance learning, short courses and vocational training.</p>
42
+ <p><a href="#">Visit My World of Work to search for training courses</a>.</p>
43
+ <p>You can also <a href="#">search for training courses, and funding towards training</a>.</p>
44
+ </Tabs.Item>,
45
+ <Tabs.Item key="bar" tabLabel="Choosing apprenticeships">
46
+ <h3>Choosing an apprenticeship for your business</h3>
47
+ <p>Apprenticeships can help you address skills gaps in your business. The government provides help with the cost of training an apprentice.</p>
48
+ <p>There are 3 different types of apprenticeship:</p>
49
+ <ul>
50
+ <li>Foundation Apprenticeships let school or college students do short-term work experience at your business as part of a qualification</li>
51
+ <li>Modern Apprenticeships let your new or current employees gain a qualification while working in a paid role at your business</li>
52
+ <li>Graduate Apprenticeships let your new or current employees gain a degree while working in a paid role at your business</li>
53
+ </ul>
54
+ <p>You can find more information on the <a href="#">apprenticeships.scot</a> website.</p>
55
+ </Tabs.Item>,
56
+ <Tabs.Item key="baz" tabLabel="Extra skills support">
57
+ <h3>Extra skills support</h3>
58
+ <p>The <a href="#">Skills for Growth</a> service can offer skills advice to businesses with fewer than 250 employees.</p>
59
+ <p>Businesses of any size can get skills advice by completing a <a href="#">skills support request form</a>.</p>
60
+ <p>Businesses of any size can also get skills advice by calling Skills Development Scotland on 0800 783 6000.</p>
61
+ </Tabs.Item>
62
+ ],
63
+ title: 'My tabs'
64
+ }
65
+ } satisfies Meta<typeof Tabs>;
66
+
67
+ export default meta;
68
+ type Story = StoryObj<typeof meta>;
69
+
70
+ export const Default: Story = {
71
+
72
+ };
73
+
74
+ export const ManualActivation: Story = {
75
+ args: {
76
+ isManual: true
77
+ }
78
+ };
79
+
80
+ export const NoBorder: Story = {
81
+ args: {
82
+ isBorderless: true
83
+ }
84
+ };
85
+
86
+ export const DifferentHeadingLevel: Story = {
87
+ args: {
88
+ headingLevel: 'h4'
89
+ }
90
+ };
@@ -1,7 +1,6 @@
1
1
  import { test, expect } from 'vitest';
2
2
  import { render, screen, within } from '@testing-library/react';
3
3
  import Tabs from './Tabs';
4
- import slugify from '../../utils/slugify';
5
4
 
6
5
  test('tab container renders correctly', () => {
7
6
  render(
@@ -62,13 +61,12 @@ test('tab container renders correctly', () => {
62
61
  //expect(tabPanelOne.tabIndex).toEqual(0);
63
62
 
64
63
  // tab panels have ID
65
- expect(tabPanelOne).toHaveAttribute('id');
66
- expect(tabPanelTwo).toHaveAttribute('id');
64
+ expect(tabPanelOne.id).not.toEqual(tabPanelTwo.id);
67
65
  });
68
66
 
69
67
  test('non-bordered tabs', () => {
70
68
  render(
71
- <Tabs data-testid="tabcontainer" bordered={false}>
69
+ <Tabs data-testid="tabcontainer" isBorderless>
72
70
  <Tabs.Item tabLabel="Tab 1" data-testid="tabpanel1">
73
71
  <div data-testid="tabpanel1content">Content one</div>
74
72
  </Tabs.Item>
@@ -146,8 +144,8 @@ test('custom baseID', () => {
146
144
  // default title slugified to part of the ID
147
145
  expect(tabHeading).toHaveAttribute('id', `${BASE_ID}-heading`);
148
146
  // generated IDs using the slug of the tab title
149
- expect(tabPanelOne).toHaveAttribute('id', `${BASE_ID}-tab-1`);
150
- expect(tabPanelTwo).toHaveAttribute('id', `${BASE_ID}-tab-2`);
147
+ expect(tabPanelOne.id.indexOf(BASE_ID)).toBeGreaterThan(-1);
148
+ expect(tabPanelTwo.id.indexOf(BASE_ID)).toBeGreaterThan(-1);
151
149
  });
152
150
 
153
151
  test('tab with and without specific ID attribute', () => {
@@ -169,13 +167,13 @@ test('tab with and without specific ID attribute', () => {
169
167
  const tabPanelOne = screen.getByTestId('tabpanel1');
170
168
  const tabPanelTwo = screen.getByTestId('tabpanel2');
171
169
 
172
- expect(tabPanelOne).toHaveAttribute('id', `${BASE_ID}-${slugify(TAB_LABEL)}`);
170
+ expect(tabPanelOne).toHaveAttribute('id');
173
171
  expect(tabPanelTwo).toHaveAttribute('id', TAB_ID);
174
172
  });
175
173
 
176
174
  test('with manual activation', () => {
177
175
  render(
178
- <Tabs data-testid="tabcontainer" manual>
176
+ <Tabs data-testid="tabcontainer" isManual>
179
177
  <Tabs.Item title="Tab 1" data-testid="tabpanel1">
180
178
  <div data-testid="tabpanel1content">Content one</div>
181
179
  </Tabs.Item>
@@ -1,11 +1,10 @@
1
- import React, { Children, useEffect, useRef } from 'react';
1
+ import React, { Children, useEffect, useRef, useId } from 'react';
2
2
  import WrapperTag from '../../common/WrapperTag';
3
3
  // @ts-ignore
4
4
  import DSTabs from '@scottish-government/design-system/src/components/tabs/tabs';
5
- import slugify from '../../utils/slugify';
6
5
 
7
6
  const TabItem = ({
8
- bordered,
7
+ isBorderless,
9
8
  children,
10
9
  className,
11
10
  id,
@@ -16,7 +15,7 @@ const TabItem = ({
16
15
  <div
17
16
  className={[
18
17
  'ds_tabs__content',
19
- bordered && 'ds_tabs__content--bordered',
18
+ !isBorderless && 'ds_tabs__content--bordered',
20
19
  className
21
20
  ].join(' ')}
22
21
  id={id}
@@ -40,11 +39,11 @@ const TabListItem = ({
40
39
 
41
40
  const Tabs = ({
42
41
  baseId = 'tabs',
43
- bordered = true,
44
42
  children,
45
43
  className,
46
44
  headingLevel = 'h2',
47
- manual = false,
45
+ isBorderless,
46
+ isManual = false,
48
47
  title = 'Contents',
49
48
  ...props
50
49
  }: SGDS.Component.Tabs) => {
@@ -63,8 +62,8 @@ const Tabs = ({
63
62
 
64
63
  if (thisChild && thisChild.type === TabItem) {
65
64
  return React.cloneElement(thisChild, {
66
- bordered: bordered,
67
- id: thisChild.props.id || `${baseId}-${slugify(thisChild.props.tabLabel)}`,
65
+ isBorderless: !!isBorderless,
66
+ id: thisChild.props.id || `${baseId}-${useId()}`,
68
67
  });
69
68
  }
70
69
  });
@@ -79,7 +78,7 @@ const Tabs = ({
79
78
  <div
80
79
  className={[
81
80
  'ds_tabs',
82
- manual && 'ds_tabs--manual',
81
+ isManual && 'ds_tabs--manual',
83
82
  className
84
83
  ].join(' ')}
85
84
  ref={ref}
@@ -0,0 +1,25 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+
3
+ import Tag from './Tag';
4
+
5
+ const meta = {
6
+ title: 'Components/Tag',
7
+ component: Tag,
8
+ argTypes: {
9
+ colour: {
10
+ control: { type: 'select' },
11
+ description: 'The tag colour to use',
12
+ options: ['', 'blue', 'green', 'grey', 'orange', 'pink', 'purple', 'red', 'teal', 'yellow'],
13
+ type: 'string'
14
+ },
15
+ },
16
+ } satisfies Meta<typeof Tag>;
17
+
18
+ export default meta;
19
+ type Story = StoryObj<typeof meta>;
20
+
21
+ export const Default: Story = {
22
+ args: {
23
+ children: 'Status',
24
+ },
25
+ };
@@ -0,0 +1,129 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import TaskList from './TaskList';
5
+
6
+ const meta = {
7
+ title: 'Components/Task list',
8
+ component: TaskList,
9
+ argTypes: {
10
+ headingId: {
11
+ description: 'ID of the task list\'s heading element',
12
+ type: 'string'
13
+ },
14
+ linkComponent: argTypes.linkComponent(),
15
+ title: {
16
+ description: 'The title of the task list',
17
+ type: {
18
+ name: 'string',
19
+ required: true
20
+ }
21
+ },
22
+ children: argTypes.children()
23
+ },
24
+ args: {
25
+ title: 'Application incomplete'
26
+ }
27
+ } satisfies Meta<typeof TaskList>;
28
+
29
+ export default meta;
30
+ type Story = StoryObj<typeof meta>;
31
+
32
+ export const Default: Story = {
33
+ render: (args) => (
34
+ <TaskList {...args}>
35
+ <TaskList.Item
36
+ href="#conditions"
37
+ id="task-conditions"
38
+ isComplete
39
+ statusText="Completed"
40
+ title="Conditions"
41
+ >
42
+ Tell us about your conditions, symptoms and any sensory issues you have.
43
+ </TaskList.Item>
44
+ <TaskList.Item
45
+ href="#in-progress"
46
+ id="task-medications"
47
+ statusText="In progress"
48
+ title="Medications"
49
+ >
50
+ Tell us about any medication you need.
51
+ </TaskList.Item>
52
+ <TaskList.Item
53
+ id="task-contacts"
54
+ statusText="Cannot start yet"
55
+ title="Contacts and supporting information"
56
+ >
57
+ Share any supporting documents and provide details of people we can talk to about you.
58
+ </TaskList.Item>
59
+ </TaskList>
60
+ )
61
+ };
62
+
63
+ export const Groups: Story = {
64
+ render: (args) => (
65
+ <TaskList {...args}>
66
+ <TaskList.Group title="Provide your health details">
67
+ <TaskList.Item
68
+ href="#conditions"
69
+ id="task-conditions"
70
+ isComplete
71
+ statusText="Completed"
72
+ title="Conditions"
73
+ >
74
+ Tell us about your conditions, symptoms and any sensory issues you have.
75
+ </TaskList.Item>
76
+ <TaskList.Item
77
+ href="#in-progress"
78
+ id="task-medications"
79
+ isComplete
80
+ statusText="Completed"
81
+ title="Medications"
82
+ >
83
+ Tell us about any medication you need.
84
+ </TaskList.Item>
85
+ <TaskList.Item
86
+ href="#contacts"
87
+ id="task-contacts"
88
+ isComplete
89
+ statusText="Completed"
90
+ title="Contacts and supporting information"
91
+ >
92
+ Share any supporting documents and provide details of people we can talk to about you.
93
+ </TaskList.Item>
94
+ </TaskList.Group>
95
+ <TaskList.Group
96
+ intro="This information will be used to check what additional benefits you may be able to apply for."
97
+ title="Tell us about your daily living and mobility circumstances"
98
+ >
99
+ <TaskList.Item
100
+ href="#preparing-food"
101
+ id="task-preparing-food"
102
+ statusText="In progress"
103
+ tagColour="grey"
104
+ title="Preparing food"
105
+ >
106
+ Questions about your ability to prepare a simple meal safely and any help you need to do this.
107
+ </TaskList.Item>
108
+ <TaskList.Item
109
+ href="#taking-nutrition"
110
+ id="task-taking-nutrition"
111
+ statusText="Not started"
112
+ tagColour="grey"
113
+ title="Taking nutrition"
114
+ >
115
+ Questions about your ability to eat and drink and any help you need to do this.
116
+ </TaskList.Item>
117
+ <TaskList.Item
118
+ href="#managing-therapy"
119
+ id="task-managing-therapy"
120
+ statusText="Not started"
121
+ tagColour="grey"
122
+ title="Managing therapy or monitoring a health condition"
123
+ >
124
+ Questions about any help you need to monitor changes in your health condition, take medication or do therapy at home.
125
+ </TaskList.Item>
126
+ </TaskList.Group>
127
+ </TaskList>
128
+ )
129
+ };
@@ -0,0 +1,123 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import argTypes from '../../../.storybook/sgdsArgTypes';
3
+
4
+ import TextInput from './TextInput';
5
+
6
+ const meta = {
7
+ title: 'Components/Text input',
8
+ component: TextInput,
9
+ argTypes: {
10
+ buttonIcon: {
11
+ control: { type: 'select' },
12
+ description: 'Name of the icon to use',
13
+ options: ['ArrowUpward', 'CalendarToday', 'Cancel', 'CheckCircle', 'ChevronLeft', 'ChevronRight', 'Close', 'Description', 'DoubleChevronLeft', 'DoubleChevronRight', 'Error', 'ExpandLess', 'ExpandMore', 'List', 'Menu', 'PriorityHigh', 'Search'],
14
+ type: 'string'
15
+ },
16
+ buttonText: {
17
+ desctiption: 'Text content for the button',
18
+ type: 'string'
19
+ },
20
+ countThreshold: argTypes.countThreshold(),
21
+ currencySymbol: {
22
+ description: 'Currency symbol to use (default is \'£\')',
23
+ type: 'string'
24
+ },
25
+ errorMessage: argTypes.errorMessage(),
26
+ hasButton: {
27
+ control: 'boolean',
28
+ description: 'Whether the component has an associated button',
29
+ type: 'boolean'
30
+ },
31
+ isCurrency: {
32
+ control: 'boolean',
33
+ description: 'Whether the component is a currency field',
34
+ type: 'boolean'
35
+ },
36
+ hasError: argTypes.hasError(),
37
+ hintText: argTypes.hintText(),
38
+ id: argTypes.id(),
39
+ label: argTypes.label(),
40
+ maxlength: argTypes.maxlength(),
41
+ name: {type: 'string'},
42
+ onBlur: argTypes.onBlur(),
43
+ onChange: argTypes.onChange(),
44
+ placeholder: {type: 'string'},
45
+ type: {
46
+ control: { type: 'select' },
47
+ options: ['date', 'datetime-local', 'email', 'month', 'number', 'password', 'search', 'tel', 'text', 'time', 'url', 'week'],
48
+ type: {
49
+ required: true,
50
+ name: 'string'
51
+ }
52
+ },
53
+ value: {type: 'string'},
54
+ width: argTypes.inputWidth()
55
+ },
56
+ args: {
57
+ id: 'first-name',
58
+ label: 'First name'
59
+ }
60
+ } satisfies Meta<typeof TextInput>;
61
+
62
+ export default meta;
63
+ type Story = StoryObj<typeof meta>;
64
+
65
+ export const Default: Story = {
66
+
67
+ };
68
+
69
+ export const KitchenSink: Story = {
70
+ args: {
71
+ countThreshold: 50,
72
+ errorMessage: 'This field is required',
73
+ hasError: true,
74
+ hintText: 'Please enter your first or given name',
75
+ id: 'kitchensink',
76
+ maxlength: 20,
77
+ value: 'Cholmondley',
78
+ width: 'fixed-20'
79
+ }
80
+ };
81
+
82
+ export const Currency: Story = {
83
+ args: {
84
+ currencySymbol: '$',
85
+ id: 'price',
86
+ isCurrency: true,
87
+ label: 'Price per unit',
88
+ placeholder: '0.00',
89
+ step: '.01',
90
+ type: 'number',
91
+ width: 'fluid-one-quarter'
92
+ }
93
+ }
94
+
95
+ export const WithButton: Story = {
96
+ args: {
97
+ buttonIcon: 'Search',
98
+ buttonText: 'Search',
99
+ hasButton: true,
100
+ id: 'withbutton'
101
+ }
102
+ }
103
+
104
+ export const Blur: Story = {
105
+ args: {
106
+ onBlur: () => {console.log('text input blur')}
107
+ },
108
+ play: async ({ canvas, userEvent }) => {
109
+ await userEvent.click(canvas.getByRole('textbox'));
110
+ await userEvent.tab();
111
+ }
112
+ }
113
+
114
+ export const Change: Story = {
115
+ args: {
116
+ onChange: () => {console.log('text input change')}
117
+ },
118
+ play: async ({ canvas, userEvent }) => {
119
+ await userEvent.click(canvas.getByRole('textbox'));
120
+ await userEvent.type(canvas.getByRole('textbox'),'banana');
121
+ await userEvent.tab();
122
+ }
123
+ }
@@ -101,7 +101,7 @@ test('text input with currency', () => {
101
101
  <TextInput
102
102
  id={INPUT_ID}
103
103
  label={LABEL_TEXT}
104
- currency
104
+ isCurrency
105
105
  />
106
106
  );
107
107
 
@@ -120,8 +120,8 @@ test('text input with custom currency symbol', () => {
120
120
  <TextInput
121
121
  id={INPUT_ID}
122
122
  label={LABEL_TEXT}
123
- currency
124
123
  currencySymbol={CURRENCY_SYMBOL}
124
+ isCurrency
125
125
  />
126
126
  );
127
127
 
@@ -13,7 +13,7 @@ const TextInput = ({
13
13
  className,
14
14
  countThreshold,
15
15
  width,
16
- currency,
16
+ isCurrency,
17
17
  currencySymbol,
18
18
  errorMessage,
19
19
  hasButton = false,
@@ -33,7 +33,7 @@ const TextInput = ({
33
33
  const errorMessageId = `error-message-${id}`;
34
34
  const hintTextId = `hint-text-${id}`;
35
35
  const ref = useRef(null);
36
- const inputWrapperClasses = `${hasButton ? 'ds_input__wrapper ds_input__wrapper--has-icon' : ''} ${currency ? 'ds_currency-wrapper' : ''}`;
36
+ const inputWrapperClasses = `${hasButton ? 'ds_input__wrapper ds_input__wrapper--has-icon' : ''} ${isCurrency ? 'ds_currency-wrapper' : ''}`;
37
37
  const describedbys: string[] = [];
38
38
 
39
39
  if (hintText) { describedbys.push(hintTextId) };
@@ -64,9 +64,9 @@ const TextInput = ({
64
64
  >
65
65
  <label className="ds_label" htmlFor={id}>{label}</label>
66
66
  {hintText && <HintText id={hintTextId} text={hintText} />}
67
- {errorMessage && <ErrorMessage id={errorMessageId} text={errorMessage}/>}
67
+ {errorMessage && <ErrorMessage id={errorMessageId}>{errorMessage}</ErrorMessage>}
68
68
  <ConditionalWrapper
69
- condition={hasButton || typeof currency !== 'undefined' && currency}
69
+ condition={hasButton || typeof isCurrency !== 'undefined' && isCurrency}
70
70
  wrapper={(children: React.JSX.Element) => <div className={inputWrapperClasses} data-symbol={currencySymbol}>{children}</div>}
71
71
  >
72
72
  <input
@@ -88,7 +88,7 @@ const TextInput = ({
88
88
  type={type}
89
89
  {...props}
90
90
  />
91
- {hasButton && (buttonText || buttonIcon) && <Button iconOnly icon={buttonIcon}>{buttonText}</Button>}
91
+ {hasButton && (buttonText || buttonIcon) && <Button isIconOnly icon={buttonIcon}>{buttonText}</Button>}
92
92
  </ConditionalWrapper>
93
93
  </ConditionalWrapper>
94
94
  );